本篇我们来构建一些常见的运维场景中可能会用到的工具镜像。将这些工具容器化,可以方便地在不同环境(如本地、CI/CD 流水线)中以一致的方式运行它们。这些镜像通常可以归类为我们在设计篇中提到的 工具层 (Tools Layer) 镜像。
Ansible 执行环境镜像
Ansible 是一个广泛使用的 IT 自动化工具,用于配置管理、应用部署、任务编排等。构建一个包含 Ansible 的 Docker 镜像,可以方便地在 CI/CD 流水线或其他自动化脚本中调用 Ansible 来执行 Playbook,而无需在宿主机上安装 Ansible 及其依赖。
新建ansible目录
mkdir -p common/tools/ansible
cd common/tools/ansible
Dockerfile 示例 (common/tools/ansible/Dockerfile):
#syntax=harbor.leops.local/library/docker/dockerfile:1
FROM harbor.leops.local/common/tools/python:3
ARG ANSIBLE_VERSION=11.5.0
LABEL org.opencontainers.image.authors="ops@leops.local" \
org.opencontainers.image.source="http://git.leops.local/ops/dockerfiles-base/common/tools/ansible/Dockerfile" \
org.opencontainers.image.description="Minimal base tools for ansible applications with non-root user."
RUN \
set -exu; \
# 创建非root用户,增强安全性
groupadd -r nonroot; \
useradd -r -m -g nonroot nonroot; \
apt-get update; \
# 安装基础工具和SSH客户端
apt-get install -y --no-install-recommends \
openssl \
openssh-client; \
# 安装指定版本的Ansible
pip3 install --no-cache-dir ansible==${ANSIBLE_VERSION}; \
# 验证安装并创建基础配置
ansible --version; \
mkdir /etc/ansible; \
ansible-config init --disabled -t all > /etc/ansible/ansible.cfg; \
# 清理临时文件,减小镜像体积
apt-get clean; \
rm -rf /var/cache/apt/archives/* /var/lib/apt/lists/* /tmp/* /var/tmp/*; \
truncate -s 0 /var/log/*log;
# 切换到非root用户,提高安全性
USER nonroot:nonroot
构建脚本示例 (common/tools/ansible/build.sh):
#!/bin/bash
set -e
# 配置
REGISTRY="harbor.leops.local"
IMAGE_BASE_NAME="common/tools/ansible"
VERSION="11.5.0"# Ansible版本
# 声明镜像地址数组
declare -a IMAGE_PATHS
IMAGE_PATHS+=(
"${REGISTRY}/${IMAGE_BASE_NAME}:${VERSION}" # 完整版本号标签
"${REGISTRY}/${IMAGE_BASE_NAME}:${VERSION%.*}" # 次版本号标签
"${REGISTRY}/${IMAGE_BASE_NAME}:${VERSION%%.*}"# 主版本号标签
)
build_image() {
echo "Building and pushing image:"
for img in "${IMAGE_PATHS[@]}"; do echo -e " $img"; done
# 构建镜像
docker buildx build \
$(for img in "${IMAGE_PATHS[@]}"; do echo -n "-t $img "; done) \
--label "org.opencontainers.image.created=$(date --rfc-3339=seconds)" \
--build-arg "ANSIBLE_VERSION=${VERSION}" \
--add-host nexus.leops.local=192.168.77.140 \
--provenance=false \
--pull \
--push \
.
echo "Build complete."
}
# 参数处理
case "$1" in
"list-tags")
# 输出镜像标签列表
printf '%s\n' "${IMAGE_PATHS[@]}"
;;
*)
build_image
;;
esac
如何使用?
# 假设你的Playbook在当前目录的playbook.yml文件中
docker run --rm -it \
# 挂载当前目录到容器的/ansible目录
-v $(pwd):/ansible \
# 挂载SSH密钥,用于Ansible连接远程主机
-v ~/.ssh/id_rsa:/root/.ssh/id_rsa:ro \
# 挂载主机清单文件
-v $(pwd)/inventory:/etc/ansible/hosts \
harbor.leops.local/common/tools/ansible:11.5.0 \
# 执行playbook命令
ansible-playbook playbook.yml -i inventory
Docker CLI 工具镜像 (用于 CI/CD)
在 CI/CD 流水线中,我们经常需要执行 Docker 命令来构建、推送或管理镜像和容器。虽然可以直接在 Runner 上安装 Docker,但有时使用一个包含 Docker CLI (和 buildx 插件) 的工具镜像会更方便、更隔离,并且能确保所有环境使用一致版本的 Docker CLI。
重要提示: 这种镜像不包含 Docker 引擎本身。它需要通过挂载宿主机的 Docker Socket (/var/run/docker.sock) 来与宿主机的 Docker 引擎通信。这种方式称为 Docker-out-of-Docker (DooD),相比 Docker-in-Docker (DinD) 通常更推荐,因为它避免了嵌套虚拟化的性能开销,并且能共享宿主机的镜像缓存。但也需要注意这种方式存在权限和安全风险,因为容器可以通过 Docker Socket 完全控制宿主机的 Docker 服务。
新建docker-cli目录
mkdir -p common/tools/docker-cli
cd common/tools/docker-cli
Dockerfile 示例 (common/tools/docker-cli/Dockerfile):
#syntax=harbor.leops.local/library/docker/dockerfile:1
FROM harbor.leops.local/common/os/debian:bullseye
ARG DOCKER_VERSION=28.1.1
LABEL org.opencontainers.image.authors="ops@leops.local" \
org.opencontainers.image.source="http://git.leops.local/ops/dockerfiles-base/common/tools/docker-cli/Dockerfile" \
org.opencontainers.image.description="Docker CLI tools"
# 启用BuildKit以加速构建过程
ENV DOCKER_BUILDKIT=1
# 安装Docker CLI和buildx插件
RUN set -eux; \
# 添加Docker官方源(这里使用阿里云镜像加速)
echo "deb [trusted=yes] https://mirrors.aliyun.com/docker-ce/linux/debian bullseye stable" > /etc/apt/sources.list.d/docker-ce.list; \
apt-get update; \
# 安装Docker CLI和buildx插件,指定版本以确保一致性
apt-get install -y -qq --no-install-recommends git docker-buildx-plugin docker-ce-cli=5:${DOCKER_VERSION}-1~debian.11~bullseye; \
# 清理缓存文件,减小镜像体积
apt-get clean; \
rm -rf /var/cache/apt/archives/* /var/lib/apt/lists/* /tmp/* /var/tmp/*; \
truncate -s 0 /var/log/*log;
构建脚本示例 (common/tools/docker-cli/build.sh):
#!/bin/bash
set -e
# 配置
REGISTRY="harbor.leops.local"
IMAGE_BASE_NAME="common/tools/docker-cli"
VERSION="28.1.1"# Docker CLI版本
# 声明镜像地址数组
declare -a IMAGE_PATHS
IMAGE_PATHS+=(
"${REGISTRY}/${IMAGE_BASE_NAME}:${VERSION}" # 完整版本号标签
"${REGISTRY}/${IMAGE_BASE_NAME}:${VERSION%.*}" # 次版本号标签(28.1)
"${REGISTRY}/${IMAGE_BASE_NAME}:${VERSION%%.*}"# 主版本号标签(28)
)
build_image() {
echo "Building and pushing image:"
for img in "${IMAGE_PATHS[@]}"; do echo -e " $img"; done
# 构建镜像
docker buildx build \
$(for img in "${IMAGE_PATHS[@]}"; do echo -n "-t $img "; done) \
--label "org.opencontainers.image.created=$(date --rfc-3339=seconds)" \
--build-arg "DOCKER_VERSION=${VERSION}" \
--provenance=false \
--pull \
--push \
.
echo "Build complete."
}
# 参数处理
case "$1" in
"list-tags")
# 输出镜像标签列表
printf '%s\n' "${IMAGE_PATHS[@]}"
;;
*)
build_image
;;
esac
如何使用 (示例: 在 CI/CD 中构建镜像)?
# 假设 CI/CD Runner 环境可以挂载 Docker Socket
docker run --rm \
# 挂载 Docker Socket,使容器内的Docker CLI能与宿主机Docker引擎通信
-v /var/run/docker.sock:/var/run/docker.sock \
# 挂载项目代码 (构建上下文)
-v $(pwd):/workspace \
# 指定工作目录
-w /workspace \
harbor.leops.local/common/tools/docker-cli:28.1.1 \
# 在容器内执行 docker build 命令
docker build -t myapp:ci-build .
安全提示: 在生产环境中使用 DooD 模式时,建议:
- 使用最小权限原则,只挂载必要的目录
- 考虑使用 Docker 插件如docker-socket-proxy限制对 Docker Socket 的访问权限
- 仅在可信环境中使用此方式
transfer.sh 文件传输服务
transfer.sh 是一个简单、轻量级的文件分享服务。你可以自己部署一个实例,方便在服务器之间或与他人快速分享文件,无需复杂的文件服务器配置。这部分是部署一个独立服务,而非构建工具镜像。
部署步骤
- 创建数据存储目录:
mkdir -p /data/transfer/data # data目录用于存储上传的文件
cd /data/transfer
- Docker Compose 配置文件 (/data/transfer/docker-compose.yml):
services:
transfer:
container_name: transfer
image: dutchcoders/transfer.sh:latest
command: --provider local --basedir /data/ --temp-path /data/
restart: always
ports:
- '8085:8080' # 将容器的8080端口映射到主机的8085端口
volumes:
- ./data:/data # 挂载数据目录
- '/usr/share/zoneinfo/Asia/Shanghai:/etc/localtime' # 设置正确的时区
- 启动服务:
docker compose up -d # 后台运行服务
- 配置 Nginx 反向代理:
创建 Nginx 配置文件 /data/nginx/nginx_data/conf.d/transfer.conf:
server {
listen 80;
server_name transfer.leops.local; # 服务域名,需要在DNS或hosts文件中配置
access_log /var/log/nginx/transfer_access.log;
error_log /var/log/nginx/transfer_error.log;
location / {
proxy_pass http://192.168.77.140:8085; # transfer.sh服务地址和端口
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 关闭缓冲,适用于文件传输场景
proxy_buffering off;
proxy_request_buffering off;
# 设置较长的超时时间,适合大文件传输
proxy_send_timeout 900;
proxy_read_timeout 900;
}
}
创建完配置文件后,重新加载 Nginx 配置:
# 在运行 Nginx 的服务器上执行
docker exec nginx-proxy sh -c "nginx -t && nginx -s reload"
使用示例
以下是如何使用这个服务的基本示例:
# 上传文件,返回一个下载链接
curl --upload-file ./myfile.txt http://transfer.leops.local/myfile.txt
# 下载文件
wget <返回的下载链接>
# 也可以通过浏览器访问服务并上传下载文件
# 在浏览器中打开: http://transfer.leops.local
版本控制
完成配置后,记得将所有文件提交到 Git 仓库进行版本控制:
git add -A .
git commit -m "feat: add 运维工具"
git push
通过构建这些标准化的运维工具镜像,可以提高自动化脚本和 CI/CD 流水线的健壮性和可移植性。容器化工具不仅解决了环境依赖问题,还确保了工具版本的一致性和可控性,特别适合在多环境、多团队协作的企业中使用。