Bootstrap

【已解决】如何让容器内的应用程序使用代理?

首先,按照这种配置方法,即通过在 /etc/systemd/system/docker.service.d/http-proxy.conf 中设置代理,它只会影响 Docker 守护进程本身,并不会自动影响 Docker 容器内部的软件或容器中的网络行为。 这意味着:

  • Docker 守护进程会通过代理访问外部资源(如拉取镜像、访问外部 API 等)。
  • 但容器内部的网络流量(例如,容器内运行的应用程序)并不会自动使用主机上的 HTTP 代理。

为什么容器内部不会自动使用代理?

  • Docker 容器内的环境变量与宿主机(主机)的环境变量是隔离的。
  • 即使 Docker 守护进程(Docker daemon)配置了 HTTP 代理,容器内的应用程序或服务仍然不会知道这些代理设置,除非显式地为容器指定代理。

如何让容器内的应用程序使用代理?

如果你在容器中修改了 ~/.bash_profile 来配置代理,重启容器后代理配置不会自动生效,因为 ~/.bash_profile 仅在登录时加载,并且会话结束后失效。

为什么代理配置不会自动生效?

  1. 容器重启后~/.bash_profile 只会在交互式登录 shell 启动时被加载(即通过 docker exec 进入容器时)。但是,容器重启时,环境变量设置并不会自动保存到新的会话中。
  2. 容器不是持久化的:容器重启后,它会恢复到原始的镜像状态,并不会自动保留容器内部的文件更改。

解决方案

方法 1:使用 Dockerfile 设置代理 为了确保代理配置在容器重启时仍然生效,你可以将代理配置写入 Dockerfile 中,这样每次容器启动时都会自动应用这些环境变量。
  1. 修改 Dockerfile: 在 Dockerfile 中,使用 ENV 指令设置代理:
 ENV http_proxy=http://<公网IP>:20172 #差点写成127.0.0.1好险
 ENV https_proxy=http://<公网IP>:20172 #自行修改IP:端口
 ENV no_proxy=localhost,127.0.0.1 
  1. 重新构建镜像
    docker build -t <new_image_name> .
  2. 重新启动容器: 使用新的镜像启动容器:
    docker run -d --name <container_name> <new_image_name>
    这样,无论容器是否重启,代理配置都会自动生效。
方法 2:修改 /etc/profile/etc/environment(全局配置)

如果你不想通过 Dockerfile 重建镜像,也可以修改容器内的全局配置文件,例如 /etc/profile/etc/environment

  1. 进入容器并编辑 /etc/profile
 docker exec -it <container_name> /bin/bash 
 vi /etc/profile 
  1. 添加代理配置: 在文件末尾添加:
 export http_proxy=http://<公网IP>:<端口> 
 export https_proxy=http://<公网IP>:<端口> 
 export no_proxy=localhost,127.0.0.1 
  1. 保存并生效: 保存后,运行以下命令使配置立即生效:
    source /etc/profile
  2. 重启容器: 容器重启后,这些配置会生效 ,因为它们是全局环境变量。
方法 3:在 docker run 时指定代理环境变量

你也可以通过 docker run 命令在启动容器时直接指定环境变量:

 docker run -d \
  -e http_proxy=http://<公网IP>:20172 \
   -e https_proxy=http://<公网IP>:20172 \
    -e no_proxy=localhost,127.0.0.1 \
     --name <container_name> \
      <image_name> 

这种方法适用于容器每次启动时都需要使用代理。


总结

  • ~/.bash_profile 配置:重启容器后不会自动生效。
  • 通过修改容器内的 /etc/profile/etc/environment 来使所有用户和会话都能自动生效?痴心妄想!本人实测。
  • 不过你可以尝试创建自定义的启动脚本,并在其中包含你需要执行的环境设置或其他初始化操作。然后,将这个脚本作为容器的启动命令或通过CMD/ENTRYPOINT指令来执行。
  • 推荐方法
    1. 通过修改 Dockerfile 中的 ENV 指令来持久化代理设置。
    1. docker run 时指定代理环境变量
    1. 容器内软件设置界面可能支持配置代理参数

通过这些方法,代理配置可以在容器重启后依然生效。

代理服务器在本机:

  1. 可以把上面提到的公网IP换成容器网关地址。不能填127.0.0.1。
ip route 	//查看路由表
docker exec -it <容器名> /bin/sh 	//进入容器
ip route 	//查看路由表
ip addr show

root@qinglong:/ql $ ip route
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 scope link src 172.17.0.2
root@qinglong:/ql $ ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
26: eth0@if27: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
root@qinglong:/ql $ exit

[root@VM-0-11-centos ~]# ip route
default via 10.6.0.1 dev eth0
10.6.0.0/22 dev eth0 proto kernel scope link src 10.6.0.11
10.8.0.0/24 dev tun0 proto kernel scope link src 10.8.0.1
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1

  1. 检查容器网络模式
    如果 Docker 容器使用的是 host 网络模式(通过 --network=host 启动),代理环境变量直接影响主机的网络请求,而不是容器内部。只有这种情况,容器内部与主机的127.0.0.1 是相通的,端口都不需要映射。
docker run -d \
  --restart=always \
  --privileged \ 	#←←这个参数是绿通?VIP?
  --network=host \ 	#这里~在这里
  --name xxxx\
  -e XXXX_ADDRESS=0.0.0.0:2026新年快乐 \
  -v /lib/modules:/lib/modules:ro \
  -v /etc/resolv.conf:/etc/resolv.conf \
  -v /etc/xxxx:/etc/xxxx \
  mzzxxx/xxxx
  1. 代理设置为内网IP有没有网络?,进入容器内部测试:
$ docker exec -it bxxx /bin/sh
$ cat /etc/os-release 		#查询系统OS
$ apk add curl 						#基于Alpine镜像的安装curl
$ curl -I https://www.baidu.com 	#访问百度
HTTP/1.1 200 Connection established #表示有网络连接成功
;