前提条件介绍:
1.wsl2使用nat网络。
2.宿主机上启动了clash并配置了allow-lan。
3.wsl2使用的是debian12。
1.问题出现
最近在使用vscode直接把项目运行在wsl2时发现特别爽。
进而想把原来香港vps的一些dockerfile迁移至wsl2进行build。
首先在宿主机上开启了clash,并开启了allow-lan,端口设置为57087。
在wsl2中配置了代理
export http_proxy=http://172.28.176.1:57087 && export https_proxy=http://172.28.176.1:57087
172.28.176.1为宿主机ip地址【wsl网关】
接下来正常安装docker,无任何问题。具体安装过程不再赘述。可参考官方文档:
安装完成后拉取测试镜像并启动,发现问题:
docker run hello-world
查看错误日志:
journalctl -u docker|tail
日志报错为访问镜像仓库不通。
但已经开启了clash网络代理,按理说不应该出现网络不能访问的问题。随即验证是否网络真的不通:
dig docker.io
域名可以正常解析。
再使用curl验证docker仓库能否访问:
很明显也是通的。
2.问题解决
🤔那么为什么会报拉取镜像超时呢?按理说网络访问是正常的。
旋即想到了是配置的问题。
因为export作用域你当前登录的bash shell而非服务。
接下来想到了要在systemd中对docker服务进行环境变量【网络代理信息】的注入。
查看docker服务安装位置
在对/lib/systemd/system/docker.service
文件进行修改时【其实就是增加两行Environment】。
如下:
[Service]
Environment="HTTP_PROXY=http://172.28.176.1:57087"
Environment="HTTPS_PROXY=http://172.28.176.1:57087"
Environment="NO_PROXY=localhost,127.0.0.1"
修改完成后重启加载配置并重启即可。
systemctl daemon-reload
systemctl restart docker
但是,突然发现了更好的配置方式及新的知识点drop-in形式增加配置。
3.最终效果并学习了drop-in配置
🤔什么是drop-in呢?
"Drop-in" 是一个在系统管理和配置方面常用的术语,特别是在 systemd 环境中。
定义:
"Drop-in" 文件是一种补充或覆盖主配置文件的小型配置文件。工作原理:
它们允许你修改或添加配置,而不需要直接编辑原始的主配置文件。
systemd 会自动读取并应用这些 drop-in 文件的内容。
位置:
对于 systemd 服务,drop-in 文件通常放在/etc/systemd/system/[服务名].service.d/
目录下。命名:
通常以.conf
结尾,例如http-proxy.conf
。优势:
模块化:可以分离不同的配置关注点。
易于管理:可以轻松添加、删除或修改特定配置。
安全更新:原始配置文件在系统更新时不会被覆盖。
示例:
对于 Docker 服务,你可能会创建/etc/systemd/system/docker.service.d/http-proxy.conf
。内容结构:
drop-in 文件通常只包含你想要添加或修改的部分,而不是完整的配置。加载顺序:
systemd 先加载主配置文件,然后按字母顺序加载 drop-in 文件。使用场景:
当你需要自定义系统服务的配置,但又不想直接修改原始配置文件时,drop-in 文件是理想的选择。查看效果:
可以使用systemctl cat [服务名]
来查看主配置文件和所有 drop-in 文件的组合效果。使用 drop-in 文件是一种更加灵活、安全和可维护的配置方法。它允许你在不影响原始系统文件的情况下自定义服务配置,这在长期维护和系统更新时特别有用。
🤔它和直接修改服务配置相比有什么优势?
虽然理论上可以直接编辑
/lib/systemd/system/docker.service
文件,但这通常不被推荐,原因如下:
系统更新风险:
/lib/systemd/system/docker.service
是由 Docker 包管理器维护的文件。系统更新时,这个文件可能会被覆盖,导致您的自定义设置丢失。
配置管理:
直接修改原始服务文件使得跟踪和管理自定义更改变得困难。
使用
/etc/systemd/system/docker.service.d/
中的 drop-in 文件可以更清晰地管理自定义配置。最佳实践:
systemd 推荐使用 drop-in 文件来自定义服务配置,而不是直接修改原始单元文件。
版本控制和备份:
使用单独的配置文件更容易进行版本控制和备份。
灵活性:
drop-in 文件允许您只覆盖需要更改的特定设置,而不影响其他默认配置。
以drop-in的形式修改docker服务:
创建一个 Docker 服务的配置目录(如果不存在):
mkdir -p /etc/systemd/system/docker.service.d
创建一个新的配置文件来设置 HTTP 代理:
vi /etc/systemd/system/docker.service.d/http-proxy.conf
在这个文件中添加以下内容:
[Service] Environment="HTTP_PROXY=http://172.28.176.1:57087" Environment="HTTPS_PROXY=http://172.28.176.1:57087" Environment="NO_PROXY=localhost,127.0.0.1"
保存并关闭文件。
重新加载 systemd 管理器配置:
systemctl daemon-reload
重启Docker 服务:
systemctl restart docker
验证环境变量是否正确设置:
systemctl show --property=Environment docker
检查 Docker 信息中的代理设置:
docker info | grep -i proxy
配置验证:
可以看到,drop-in的方式确实把配置动态加载到了一起。
现在再拉镜像试一试。
成了,牛逼。
4.其它知识点,一并了解下
🤔/etc/systemd/system/docker.service.d/http-proxy.conf 为什么创建了这个文件,它就会注入到/lib/systemd/system/docker.service 中?
systemd 的配置层次结构:
systemd 使用一个分层的配置系统,允许在不同的层次上修改服务配置。配置文件的优先级:
/lib/systemd/system/ 包含默认的单元文件
/etc/systemd/system/ 包含系统管理员的自定义配置
/etc/systemd/system/[unit].d/ 目录包含针对特定单元的 drop-in 文件
配置合并机制:
systemd 首先读取主单元文件(如 /lib/systemd/system/docker.service)
然后它会查找并应用 /etc/systemd/system/docker.service.d/ 目录中的所有 .conf 文件
这些 .conf 文件的内容会被合并到主配置中,可以覆盖或补充原有设置
为什么不直接修改主文件:
保持原始配置文件不变有助于系统更新和维护
分离自定义配置使得管理更加清晰和安全
"注入" 的过程:
这不是真正的 "注入",而是一个动态合并的过程
当 systemd 加载服务配置时,它会自动考虑所有相关的配置文件
优势:
模块化:可以分别管理不同方面的配置
易于维护:可以轻松添加、删除或修改特定设置
兼容性:原始服务文件保持不变,减少与系统更新的冲突
工作原理:
当你运行
systemctl daemon-reload
时,systemd 重新读取所有配置它会合并主配置文件和所有相关的 drop-in 文件
最终生成的配置会被应用到服务上
查看合并后的配置:
你可以使用systemctl cat docker
命令来查看合并后的完整配置总之,/etc/systemd/system/docker.service.d/http-proxy.conf 文件不是直接"注入"到主配置文件中,而是被 systemd 动态合并到最终的服务配置中。这种方法提供了一种灵活、安全和可维护的方式来自定义系统服务,而无需修改原始的系统文件。
HTTP Proxy: http://172.28.176.1:57087
HTTPS Proxy: http://172.28.176.1:57087
No Proxy: localhost,127.0.0.1
🤔这些配置 docker怎么知道在什么时候该用什么?还是需要手动指定?
Docker 守护进程(Docker Daemon)的行为:
Docker 守护进程会在启动时读取这些代理设置。
这些设置会影响 Docker 守护进程本身的网络操作,如拉取镜像、检查更新等。
HTTP_PROXY 和 HTTPS_PROXY:
用于所有 HTTP 和 HTTPS 请求。
例如,当您执行
docker pull
命令从 Docker Hub 或其他远程仓库拉取镜像时。NO_PROXY:
指定不使用代理的地址。
对于 localhost 和 127.0.0.1 的请求,Docker 将直接连接而不使用代理。
自动应用场景:
拉取镜像(docker pull)
推送镜像(docker push)
检查远程仓库的认证信息
Docker 守护进程与 Docker Hub 或其他远程服务的通信
容器内的网络请求:
默认情况下,这些代理设置不会自动传递给容器内部。
如果需要容器内也使用代理,需要在运行容器时显式传递这些环境变量。
容器使用代理的方法:
使用 -e 参数传递环境变量:
docker run -e HTTP_PROXY=http://172.28.176.1:57087 -e HTTPS_PROXY=http://172.28.176.1:57087 ...
或在 Dockerfile 中设置:
ENV HTTP_PROXY http://172.28.176.1:57087 ENV HTTPS_PROXY http://172.28.176.1:57087
构建镜像时使用代理:
在
docker build
命令中使用 --build-arg 传递代理设置:docker build --build-arg HTTP_PROXY=http://172.28.176.1:57087 --build-arg HTTPS_PROXY=http://172.28.176.1:57087 .
覆盖默认设置:
可以在特定命令中使用环境变量来临时覆盖这些设置:
HTTP_PROXY=http://other-proxy.example.com docker pull some-image
评论区