Colima 代理
2025年5月,我在旧笔记本 MacBook Pro 15" Late 2013 重新部署 Colima 。由于时隔多时,软件堆栈有了很大的更新,我想重新实践和整理手册,修订之前 Colima代理(文章归档) 中过时的操作步骤,通过简洁有效的方式实现 越过长城 完成容器的流畅部署。
之所以需要设置Colima代理,是因为GFW屏蔽了 dockerhub 导致无法直接从开源社区获取官方镜像。例如在build镜像:
docker build --no-cache \
--build-arg UID=$(id -u) \
--build-arg GID=$(id -g) \
--rm -t debian-dev .
此时显示访问registry仓库端口超时:
[+] Building 39.5s (2/2) FINISHED
=> [internal] load build definition from Dockerfile 4.4s
=> => transferring dockerfile: 4.87kB 0.0s
=> ERROR [internal] load metadata for docker.io/library/debian:latest 30.0s
------
> [internal] load metadata for docker.io/library/debian:latest:
------
Dockerfile:1
--------------------
1 | >>> FROM debian:latest
2 |
3 | ENV container=docker
--------------------
error: failed to solve: debian:latest: failed to resolve source metadata for docker.io/library/debian:latest: failed to do request: Head "https://registry-1.docker.io/v2/library/debian/manifests/latest": dial tcp 69.63.186.30:443: i/o timeout
FATA[0040] no image was built
FATA[0041] exit status 1
未代理之前的初始部署
Colima快速起步 中采用基本启动运行方式:
qemu 模式虚拟化的 2c4g 虚拟机运行 colima# 如果macOS v14/15 ,支持Apple Virtualization,建议使用 vz (性能更好)
# colima start --runtime containerd --cpu 2 --memory 4 --vm-type=vz
# 不支持 --vm-type=vz 则是通过qemu运行
# 注意: 如果要支持代理,需要登陆到Colima虚拟机中安装docker服务并完成配置: https://cloud-atlas.readthedocs.io/zh-cn/latest/docker/colima/colima_proxy.html
colima start --runtime containerd --cpu 2 --memory 4
# 如果不指定runtime,会要求在macOS上 'brew install docker' ,我没有使用这个方法
# colima start --cpu 2 --memory 4
这里运行指定了 containerd运行时(runtime) 作为 runtime,所以Colima虚拟机内部只有
containerd一个服务,没有安装 Docker 。现在需要通过colima ssh登陆到Colima虚拟机内部完成docker服务安装:
apt update && apt -y upgrade && apt autoremove
# 安装docker服务来支持代理配置
apt -y install docker.io
Host主机代理准备
Colima使用的代理通道是在Host主机(macOS)上创建的,在macOS上执行以下命令构建 SSH隧道 :
代理配置注入虚拟机
Host主机环境变量方法
如果在执行 colima start 命令时,Host主机的环境变量中包含代理配置,例如:
export http_proxy="http://127.0.0.1:3128"
export https_proxy="http:127.0.0.1:3128"
export no_proxy="localhost,127.0.0.1,*.baidu.com,192.168.0.0/16,10.0.0.0/8"
Colima虚拟机配置文件方法
上述通过Host主机环境变量注入proxy配置的方法要求Host主机shell环境中必须有代理配置,如果这个环境变量在启动colima之前被修改就会不起作用(如果环境变量是临时手工输入的)。所以,更为可靠的方法是修订Colima配置。
修改
~/.colima/default/colima.yaml:
$HOME/.colima/default/colima.yaml 直接添加PROXY配置env:
HTTP_PROXY: http://127.0.0.1:3128
HTTPS_PROXY: http://127.0.0.1:3128
NO_PROXY: localhost,127.0.0.1,*.baidu.com,192.168.0.0/16,10.0.0.0/8
代理配置注入虚拟机的分析和要点
完成上述两种配置方法之一以后,启动的 default Colima虚拟机会自动注入代理配置,也就是 colima ssh 登陆到虚拟机内部检查 env | grep -i proxy 会看到和Host主机一样的配置:
colima 虚拟机内部检查 env 输出可以看到注入的代理配置no_proxy=localhost,127.0.0.1,*.baidu.com,192.168.0.0/16,10.0.0.0/8
NO_PROXY=localhost,127.0.0.1,*.baidu.com,192.168.0.0/16,10.0.0.0/8
HTTPS_PROXY=http://192.168.5.2:3128
HTTP_PROXY=http://192.168.5.2:3128
https_proxy=http://192.168.5.2:3128
http_proxy=http://192.168.5.2:3128
上述配置是 colima 虚拟机启动时自动添加到虚拟机内部的 /etc/environment 中实现的,即虚拟机内部可以看到动态在 /etc/environment 中添加了如下配置行:
colima 虚拟机内部 /etc/environment 中自动添加的代理配置PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin"
#LIMA-START
HTTPS_PROXY=http://192.168.5.2:3128
HTTP_PROXY=http://192.168.5.2:3128
NO_PROXY=localhost,127.0.0.1,*.baidu.com,192.168.0.0/16,10.0.0.0/8
http_proxy=http://192.168.5.2:3128
https_proxy=http://192.168.5.2:3128
no_proxy=localhost,127.0.0.1,*.baidu.com,192.168.0.0/16,10.0.0.0/8
#LIMA-END
Colima虚拟机内部容器服务的代理配置
备注
我最初在 Colima代理(文章归档) 实践中,因为不确定是 Docker 服务还是 containerd运行时(runtime) 需要代理设置,所以两者都做了配置。但是我现在重新对比验证确认:
只需要诶之docker服务的proxy代理 环境变量就可以实现镜像通过代理下载
containerd运行时(runtime) 和 nerdctl 不支持代理,所以之前实践中配置containerd的
http_proxy和https_proxy环境变量实际上并没有生效(我对比了)
在Colima虚拟机内部运行了 docker 服务(containerd不需要配置),需要为这个容器服务配置 Systemd进程管理器 服务的环境变量来传递代理配置
colima ssh登陆到Colima虚拟机内部,执行以下命令创建docker服务的环境配置:
if [ ! -d /etc/systemd/system/docker.service.d ];then
mkdir -p /etc/systemd/system/docker.service.d
fi
cat <<EOF >/etc/systemd/system/docker.service.d/http-proxy.conf
[Service]
Environment="HTTP_PROXY=${HTTP_PROXY:-}"
Environment="HTTPS_PROXY=${HTTPS_PROXY:-}"
Environment="NO_PROXY=${NO_PROXY:-localhost},${LOCAL_NETWORK}"
EOF
systemctl daemon-reload
systemctl restart docker
现在在Colima虚拟机内部,执行以下命令检查
docker服务环境配 :
systemctl show 检查 Environment 属性# systemctl show docker --property Environment
Environment=HTTP_PROXY=http://192.168.5.2:3128 HTTPS_PROXY=http://192.168.5.2:3128 "NO_PROXY=localhost,127.0.0.1,*.baidu.com,192.168.0.0/16,10.0.0.0/8,"
输出显示 docker 都已经具备了PROXY环境配置
docker客户端配置
备注
实践验证,当Colima虚拟机已经注入了 http_proxy 和 https_proxy 代理配置环境变量,依然要配置docker客户端的 config.json
docker镜像的下载要通过proxy,不仅需要 dockerd 配置代理, docker 客户端程序也需要配置代理。这是因为:
docker的meta元数据是通过
docker客户端下载的docker容器内部需要注入代理配置,否则容器内部的部分安装执行(被墙)会无法完成
备注
docker镜像内部注入代理配置也可以在 Dockerfile 中配置:
# 我觉得比较灵活的方式还是配置Docker客户端 ~/.docker/config.json
ENV HTTP_PROXY "http://172.17.0.1:3128"
ENV HTTP_PROXY "http://172.17.0.1:3128"
ENV FTP_PROXY "ftp://172.17.0.1:3128"
ENV NO_PROXY "*.baidu.com,192.168.0.0/16,10.0.0.0/8"
在
colima虚拟机内部配置~/.docker/config.json:
colima 虚拟机内部 docker 客户端使用代理 ~/.docker/config.json{
"proxies":
{
"default":
{
"httpProxy": "http://192.168.5.2:3128",
"httpsProxy": "http://192.168.5.2:3128",
"noProxy": "*.baidu.com,192.168.0.0/16,10.0.0.0/8"
}
}
}
构建容器
采用 Debian镜像(tini进程管理器) 的 debian-dev :
debian-dev包含了安装常用工具和开发环境:
FROM debian:latest
ENV container=docker
# 对于墙内用户需要构建完善的翻墙代理才能顺利执行这个Dockerfile
# 详情参考 https://cloud-atlas.readthedocs.io/zh-cn/latest/docker/colima/colima_socks_proxy.html
# 方法一: 强行让 apt-get 走内部专属的 socks5h 隧道,直接无视外界环境变量
#RUN echo 'Acquire::http::Proxy "socks5h://192.168.5.2:1080/";' > /etc/apt/apt.conf.d/proxy.conf && \
# echo 'Acquire::https::Proxy "socks5h://192.168.5.2:1080/";' >> /etc/apt/apt.conf.d/proxy.conf
# 方法二: 采用开始时CP进容器,结束时rm掉该文件
COPY apt_proxy.conf /etc/apt/apt.conf.d/proxy.conf
#RUN rm /etc/apt/apt.conf.d/proxy.conf
# 方法三: BuildKit 支持 --mount=type=bind ,可以在每一条RUN命令层动态将外部文件映射进容器,但是需要注意每一层(每一个RUN)都是独立无状态的,所以挂载在当前RUN结束时强制卸载
#RUN --mount=type=bind,source=apt_proxy.conf,target=/etc/apt/apt.conf.d/proxy.conf \
# apt update -y && apt upgrade -y
# 增加针对特定qemu的CPU模拟的编译设置
# 必须使用 ENV 固化,否则容器运行时 JIT 编译器(如 Ruby YJIT)无法继承该参数
#ENV CFLAGS="-march=x86-64-v3 -O2"
ENV LANG="en_US.UTF-8"
ENV LC_ALL="en_US.UTF-8"
ARG HTTP_PROXY="socks5h://192.168.5.2:1080"
ARG HTTPS_PROXY="socks5h://192.168.5.2:1080"
ARG ALL_PROXY="socks5h://192.168.5.2:1080"
ENV http_proxy=${HTTP_PROXY}
ENV https_proxy=${HTTPS_PROXY}
ENV all_proxy=${ALL_PROXY}
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get clean
RUN apt-get update -y
RUN apt-get upgrade -y
# Debian仓库内置tini,可以直接安装
RUN apt-get -y install tini
# Copy tini entrypoint script
COPY entrypoint_ssh_cron_bash /entrypoint.sh
RUN chmod +x /entrypoint.sh
# SSH
RUN apt-get -y install sudo passwd openssh-client openssh-server curl ca-certificates
# Utilities
RUN apt-get -y install cron tmux vim locales net-tools iproute2 dnsutils plocate gnupg2 git tree unzip lsof wget
# 开发编译依赖
RUN apt-get -y install --no-install-recommends build-essential libssl-dev libyaml-dev zlib1g-dev libgmp-dev libreadline-dev libsqlite3-dev sqlite3 libffi-dev
# neovim依赖
RUN apt-get -y install --no-install-recommends ripgrep fd-find
# 非必须,用于支持我使用的sphinx doc
RUN apt-get -y install graphviz
RUN rm -rf /var/lib/apt/lists/*
# 补全locales
RUN echo "LC_ALL=en_US.UTF-8" >> /etc/environment
RUN echo "LANG=en_US.UTF-8" >> /etc/environment
RUN echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
RUN echo "LANG=en_US.UTF-8" > /etc/locale.conf
RUN locale-gen en_US.UTF-8
RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
# add account "admin" and give sudo privilege
# uid & gid follow colima system to access HOME directory
# "docker build --build-arg UID=$(id -u) GID=$(id -g)" will override it.
ARG USER=admin
ARG GROUP=admin
ARG UID=1000
ARG GID=1000
RUN groupadd -g ${GID} ${GROUP}
RUN useradd -g ${GID} -u ${UID} -m -d /home/${USER} -s /bin/bash ${USER}
RUN adduser ${USER} sudo
RUN echo "%sudo ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
# set TIMEZONE to Shanghai
RUN unlink /etc/localtime
RUN ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# RUN mkdir /run/sshd
RUN ssh-keygen -A
USER admin
WORKDIR /home/admin
# 安装 Mise 核心,现代开发语言的万能管理器Mise托管语言栈
RUN curl https://mise.run | sh
RUN echo 'eval "$(~/.local/bin/mise activate)"' >> ~/.bashrc
# 动态将 Mise 垫片和二进制路径暴露给后续构建层和运行时环境
ENV PATH="/home/admin/.local/share/mise/shims:/home/admin/.local/bin:$PATH"
# C/C++ 在安装Cmake时会同时安装
# Rust, Go, Python, Ruby, Rails
# mise 支持命令行传递环境变量实现代理配置
#ARG PROXY_ADDRESS=192.168.5.2:1080
#RUN export all_proxy=socks5h://${PROXY_ADDRESS} && \
# export http_proxy=http://${PROXY_ADDRESS} && \
# export https_proxy=http://${PROXY_ADDRESS} && \
# mise use --global cmake@latest && \
# mise use --global rust@stable && \
# mise use --global go@1.23 && \
# mise use --global python@3.12 && \
# mise use --global ruby@3.3 && \
# gem install --no-document rails
# 采用动态挂载
RUN --mount=type=bind,source=mise_proxy.env,target=/home/admin/mise_proxy.env \
set -a && . /home/admin/mise_proxy.env && set +a && \
mise use --global cmake@latest && \
mise use --global rust@stable && \
mise use --global go@1.26 && \
mise use --global python@3.14 && \
mise use --global ruby@3 && \
mise use --global neovim@stable
# gem不支持socks代理,如果访问阻塞则改为国内源
RUN gem install --no-document rails
# LazyVim
# git 原生参数 -c http.proxy=,临时覆盖全局网络代理
RUN git clone -c http.proxy="socks5h://192.168.5.2:1080" \
https://github.com/LazyVim/starter /home/admin/.config/nvim && \
rm -rf /home/admin/.config/nvim/.git
# 通过无头模式(Headless)在构建期将插件和 LSP 彻底刷入镜像中
# 这会将所有的 LSP、Treesitter、关键插件在 Docker 构建期就物理下载到镜像的 /home/admin/.local/share/nvim 中
RUN nvim --headless "+Lazy! sync" +qa
# 预编译 Treesitter 语法树解析器(可选,防止启动时现场编译卡顿)
# 高频使用 Markdown (用于知识库) 或 Go/C++
RUN nvim --headless "+TSUpdateSync markdown python go cpp" +qa
# Mason 强行同步安装LSP,注意需要网络畅通
RUN nvim --headless -c ' \
local registry = require("mason-registry"); \
local lsp_list = { "clangd", "rust-analyzer", "gopls", "pyright", "ruff", "ruby-lsp" }; \
\
registry.refresh(function() \
for _, name in ipairs(lsp_list) do \
local p = registry.get_package(name); \
if not p:is_installed() then \
print("▶ [Mason Build-time] 正在物理拉取并编译: " .. name); \
p:install(); \
end \
end \
end); \
\
vim.wait(300000, function() \
for _, name in ipairs(lsp_list) do \
if not registry.is_installed(name) then return false end \
end \
return true \
end, 500); \
print("🎉 [Mason Build-time] 恭喜!所有多语言 LSP 语义专家已成功硬焊进镜像层!"); \
' +qa
# python program: virtualenv
RUN bash -c 'cd /home/admin && python3 -m venv venv3'
# 我使用Sphinx doc来撰写Cloud-Atlas文档,如不需要请注释
RUN bash -c 'source /home/admin/venv3/bin/activate && pip install sphinx sphinx_rtd_theme sphinxnotes-strike sphinxcontrib-video sphinxcontrib-youtube myst-parser jieba'
# entrypoint.sh 需要使用root身份执行
USER root
# run service when container started - sshd
EXPOSE 22:1122
# next.js nextra
EXPOSE 3000:13000
# Sphinx
EXPOSE 8080:18080
# Jekyll
EXPOSE 4000:14000
# HTTP
EXPOSE 80:1180
# HTTPS
EXPOSE 443:1443
# Run your program under Tini
# CMD ["/your/program", "-and", "-its", "arguments"]
CMD ["/entrypoint.sh"]
构建
debian-dev镜像:
docker build --no-cache \
--build-arg UID=$(id -u) \
--build-arg GID=$(id -g) \
--rm -t debian-dev .
运行
dev:
docker run -dt --name debian-dev --hostname debian-dev \
-p 1122:22 \
-p 13000:3000 \
-p 18080:8080 \
-p 14000:4000 \
-p 1180:80 \
-p 1443:443 \
-v /Users/admin/docs/ssh:/home/admin/.ssh \
-v /Users/admin/docs:/home/admin/docs \
debian-dev:latest
# 物理主机的 /Users/admin/secret 存放需要映射进容器的密钥以及ssh配置
# 如果需要在运行时注入环境变量,则添加类似如下参数(添加代理案例)
# -e HTTP_PROXY=http://172.17.0.1:3128 \
# -e HTTPS_PROXY=http://172.17.0.1:3128 \
# -e NO_PROXY=localhost,127.0.0.1,*.baidu.com,192.168.0.0/16,10.0.0.0/8 \
此时在Colima中运行的容器 dev 可以在macOS的Host主机上直接访问(端口1122):
ssh admin@127.0.0.1 -p 1122
在
dev容器中检查就可以看到几乎和Host主机完全一致的HOME目录访问,所有文件都具备,非常方便融合Linux+macOS工作