Skip to content

Commit 6aa3488

Browse files
[FIX] Refactor using proxy.py
1 parent ec35138 commit 6aa3488

2 files changed

Lines changed: 73 additions & 155 deletions

File tree

Dockerfile

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,45 @@
11
FROM python:3-alpine
22

3-
ENTRYPOINT ["dumb-init", "--", "/usr/local/bin/entrypoint.sh"]
4-
CMD ["proxy"]
5-
HEALTHCHECK CMD ["healthcheck"]
6-
7-
RUN apk add --no-cache -t .build build-base curl-dev && \
8-
apk add --no-cache iptables ipset iproute2 dnsmasq && \
9-
apk add --no-cache libcurl && \
10-
pip install --no-cache-dir dnspython dumb-init pycurl && \
11-
apk del .build
3+
RUN apk add --no-cache --virtual .build-deps \
4+
build-base \
5+
curl-dev \
6+
&& apk add --no-cache \
7+
dumb-init \
8+
dnsmasq \
9+
iproute2 \
10+
ipset \
11+
iptables \
12+
libcurl \
13+
&& pip install --no-cache-dir \
14+
dnspython \
15+
pycurl \
16+
&& apk del .build-deps
1217

1318
ENV NAMESERVERS="1.1.1.1 8.8.8.8" \
1419
PORT="*" \
15-
LISTEN_PORT=15000 \
16-
RESOLVE_INTERVAL=60 \
17-
PRE_RESOLVE=0 \
18-
MODE=tcp \
19-
VERBOSE=0 \
20-
MAX_CONNECTIONS=100 \
21-
UDP_ANSWERS=1 \
22-
HTTP_HEALTHCHECK=0 \
20+
LISTEN_PORT="15000" \
21+
RESOLVE_INTERVAL="60" \
22+
PRE_RESOLVE="0" \
23+
MODE="tcp" \
24+
VERBOSE="0" \
25+
MAX_CONNECTIONS="100" \
26+
UDP_ANSWERS="1" \
27+
HTTP_HEALTHCHECK="0" \
2328
HTTP_HEALTHCHECK_URL="http://\$TARGET/" \
24-
SMTP_HEALTHCHECK=0 \
29+
SMTP_HEALTHCHECK="0" \
2530
SMTP_HEALTHCHECK_URL="smtp://\$TARGET/" \
2631
SMTP_HEALTHCHECK_COMMAND="HELP" \
27-
DNS_UPSTREAMS="1.1.1.1 8.8.8.8" \
28-
RESOLVE_INTERVAL="60"
32+
DNS_UPSTREAMS="1.1.1.1 8.8.8.8"
2933

3034
COPY proxy.py /usr/local/bin/proxy
3135
COPY healthcheck.py /usr/local/bin/healthcheck
3236
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
33-
RUN chmod +x /usr/local/bin/entrypoint.sh
37+
38+
RUN chmod +x \
39+
/usr/local/bin/proxy \
40+
/usr/local/bin/healthcheck \
41+
/usr/local/bin/entrypoint.sh
42+
43+
ENTRYPOINT ["dumb-init", "--", "/usr/local/bin/entrypoint.sh"]
44+
CMD ["proxy"]
45+
HEALTHCHECK CMD ["healthcheck"]

entrypoint.sh

Lines changed: 40 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,6 @@ log() {
55
echo "[entrypoint] $*"
66
}
77

8-
run() {
9-
"$@"
10-
}
11-
12-
ip_for_iface() {
13-
iface="$1"
14-
ip -4 addr show dev "$iface" | awk '/inet /{print $2}' | cut -d/ -f1 | head -n1
15-
}
16-
17-
extract_domains_from_allowed_hosts() {
18-
for item in ${ALLOWED_HOSTS:-}; do
19-
case "$item" in
20-
"" ) ;;
21-
*[!0-9.]* ) printf '%s\n' "$item" ;;
22-
esac
23-
done | sort -u | xargs
24-
}
25-
268
detect_iface_for_gateway() {
279
gw_ip="$1"
2810
ip route get "$gw_ip" 2>/dev/null | awk '
@@ -107,17 +89,21 @@ project_containers = [
10789
if not project_containers:
10890
raise RuntimeError(f"No running containers found for project {PROJECT}")
10991
110-
odoo_container = None
92+
primary_container = None
11193
for c in project_containers:
11294
if (c.get("Labels") or {}).get("com.docker.compose.service") == PRIMARY_SERVICE:
113-
odoo_container = c
95+
primary_container = c
11496
break
11597
116-
if not odoo_container:
117-
raise RuntimeError(f"Could not find primary service {PRIMARY_SERVICE} in project {PROJECT}")
98+
if not primary_container:
99+
raise RuntimeError(
100+
f"Could not find primary service {PRIMARY_SERVICE} in project {PROJECT}"
101+
)
118102
119-
odoo_inspect = docker_get(f"/v1.41/containers/{odoo_container['Id']}/json")
120-
odoo_networks = set((odoo_inspect.get("NetworkSettings", {}).get("Networks") or {}).keys())
103+
primary_inspect = docker_get(f"/v1.41/containers/{primary_container['Id']}/json")
104+
primary_networks = set(
105+
(primary_inspect.get("NetworkSettings", {}).get("Networks") or {}).keys()
106+
)
121107
122108
lines = []
123109
seen = set()
@@ -130,7 +116,7 @@ for c in project_containers:
130116
networks = inspect.get("NetworkSettings", {}).get("Networks") or {}
131117
132118
for net_name, net_cfg in networks.items():
133-
if net_name not in odoo_networks:
119+
if net_name not in primary_networks:
134120
continue
135121
136122
ip = (net_cfg or {}).get("IPAddress")
@@ -182,19 +168,22 @@ refresh_hosts_from_docker_loop() {
182168
done &
183169
}
184170

171+
extract_domains_from_allowed_hosts() {
172+
for item in ${ALLOWED_HOSTS:-}; do
173+
case "$item" in
174+
"") ;;
175+
*[!0-9.]*) printf '%s\n' "$item" ;;
176+
esac
177+
done | sort -u | xargs
178+
}
179+
185180
start_dnsmasq_local() {
186181
dns_forwarder="$1"
187-
: "${DNS_ALLOWED_DOMAINS:=}"
188-
189-
if [ -z "$DNS_ALLOWED_DOMAINS" ]; then
190-
DNS_ALLOWED_DOMAINS="$(extract_domains_from_allowed_hosts)"
191-
fi
192182

193183
mkdir -p /run
194184
touch /run/dnsmasq-internal.hosts
195185

196186
log "local dnsmasq: forwarder=$dns_forwarder"
197-
log "local dnsmasq: allowed domains=$DNS_ALLOWED_DOMAINS"
198187

199188
cat > /etc/dnsmasq.conf <<EOF
200189
no-resolv
@@ -205,113 +194,13 @@ bind-interfaces
205194
listen-address=127.0.0.1
206195
addn-hosts=/run/dnsmasq-internal.hosts
207196
clear-on-reload
197+
server=$dns_forwarder
208198
EOF
209199

210-
for domain in $DNS_ALLOWED_DOMAINS; do
211-
echo "server=/$domain/$dns_forwarder" >> /etc/dnsmasq.conf
212-
done
213-
214200
dnsmasq -k -C /etc/dnsmasq.conf -x /run/dnsmasq.pid >/dev/null 2>&1 &
215201
log "local dnsmasq started on 127.0.0.1:53"
216202
}
217203

218-
start_dnsmasq_gateway() {
219-
: "${DNS_UPSTREAMS:=1.1.1.1 8.8.8.8}"
220-
: "${DNS_ALLOWED_DOMAINS:=}"
221-
222-
if [ -z "$DNS_ALLOWED_DOMAINS" ]; then
223-
DNS_ALLOWED_DOMAINS="$(extract_domains_from_allowed_hosts)"
224-
fi
225-
226-
log "gateway dnsmasq: upstreams=$DNS_UPSTREAMS"
227-
log "gateway dnsmasq: allowed domains=$DNS_ALLOWED_DOMAINS"
228-
229-
mkdir -p /run
230-
231-
cat > /etc/dnsmasq.conf <<EOF
232-
no-resolv
233-
bogus-priv
234-
cache-size=1000
235-
filter-AAAA
236-
EOF
237-
238-
for domain in $DNS_ALLOWED_DOMAINS; do
239-
for ns in $DNS_UPSTREAMS; do
240-
echo "server=/$domain/$ns" >> /etc/dnsmasq.conf
241-
done
242-
done
243-
244-
dnsmasq -k -C /etc/dnsmasq.conf -x /run/dnsmasq.pid >/dev/null 2>&1 &
245-
log "gateway dnsmasq started"
246-
}
247-
248-
resolve_allowed_ips_once() {
249-
python3 - <<'PY'
250-
import os
251-
import socket
252-
253-
items = os.environ.get("ALLOWED_HOSTS", "").split()
254-
ips = set()
255-
256-
for item in items:
257-
if not item:
258-
continue
259-
try:
260-
socket.inet_aton(item)
261-
ips.add(item)
262-
continue
263-
except OSError:
264-
pass
265-
266-
try:
267-
for res in socket.getaddrinfo(item, None, type=socket.SOCK_STREAM):
268-
ip = res[4][0]
269-
if ":" not in ip:
270-
ips.add(ip)
271-
except socket.gaierror:
272-
pass
273-
274-
for ip in sorted(ips):
275-
print(ip)
276-
PY
277-
}
278-
279-
setup_gateway_firewall() {
280-
: "${IPSET_NAME:=whitelist}"
281-
: "${ALLOWED_HOSTS:=}"
282-
: "${REFRESH_INTERVAL:=300}"
283-
284-
run ipset create "$IPSET_NAME" hash:ip -exist
285-
286-
resolve_allowed_ips_once | while read -r ip; do
287-
[ -n "$ip" ] && ipset add "$IPSET_NAME" "$ip" -exist || true
288-
done
289-
290-
run iptables -t nat -C POSTROUTING -j MASQUERADE 2>/dev/null || \
291-
run iptables -t nat -A POSTROUTING -j MASQUERADE
292-
293-
run iptables -C FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT 2>/dev/null || \
294-
run iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
295-
296-
run iptables -C FORWARD -m set --match-set "$IPSET_NAME" dst -j ACCEPT 2>/dev/null || \
297-
run iptables -A FORWARD -m set --match-set "$IPSET_NAME" dst -j ACCEPT
298-
299-
(
300-
while :; do
301-
resolve_allowed_ips_once | while read -r ip; do
302-
[ -n "$ip" ] && ipset add "$IPSET_NAME" "$ip" -exist || true
303-
done
304-
sleep "$REFRESH_INTERVAL"
305-
done
306-
) &
307-
}
308-
309-
gateway_mode() {
310-
start_dnsmasq_gateway
311-
setup_gateway_firewall
312-
tail -f /dev/null
313-
}
314-
315204
net_setup_mode() {
316205
echo "INFO: net_setup_mode: waiting for gateway DNS..."
317206
GW_IP="$(wait_for_gateway_resolution)"
@@ -360,10 +249,27 @@ net_setup_mode() {
360249
tail -f /dev/null
361250
}
362251

252+
proxy_mode() {
253+
# La imagen tiene CMD ["proxy"], así que quitamos ese argumento
254+
# para no pasarlo dos veces al script Python.
255+
if [ "${1:-}" = "proxy" ]; then
256+
shift
257+
fi
258+
259+
exec /usr/local/bin/proxy "$@"
260+
}
261+
363262
main() {
364263
case "${MODE_RUN:-gateway}" in
365-
gateway) gateway_mode ;;
366-
net_setup) net_setup_mode ;;
264+
net_setup)
265+
net_setup_mode
266+
;;
267+
gateway|"")
268+
proxy_mode "$@"
269+
;;
270+
legacy|tcp|proxy)
271+
proxy_mode "$@"
272+
;;
367273
*)
368274
echo "Unknown MODE_RUN=${MODE_RUN:-}" >&2
369275
exit 1

0 commit comments

Comments
 (0)