1. 区别
1.1 多阶段构建
你可以在一个 Dockerfile 中定义多个构建阶段。例如,一个阶段用来编译代码(包含所有开发依赖),另一个阶段只把编译好的产物复制到一个干净的基础镜像中。
1.2 CMD Vs. ENTRYPOINT:容器的 “ 使命 “ 与 “ 参数 “
- 想象一下,你的容器是一个 “ 命令行工具 “。
- ENTRYPOINT : 定义了这个工具的 “ 程序本身 “ 。它是固定的,是容器的核心使命。比如,这个工具就是 git 。
- CMD : 定义了这个工具的 “ 默认参数 “ 。如果用户不指定任何参数,就用这个。比如, git 的默认参数是 –help
- CMD 被覆盖,ENTRYPOINT 被用来传参数用
1 2 3 4
|
ENTRYPOINT ["docker-entrypoint.sh"] CMD ["redis-server"]
|
1.3 Volume Vs. Bind Mount
这两种都是将数据持久化到容器之外的方法,但管理方式和适用场景截然不同。
- Bind Mount (绑定挂载) : 像是你已有的 “ 私家别墅 “ 。你告诉 Docker:” 把我的这个文件夹(别墅)直接给容器用 “。你对这个文件夹有完全的控制权。
- 将主机上的文件或目录直接挂载到容器中
- ✅ 更好的可移植性
- Volume (数据卷) : 像是 Docker 为你管理的 “ 精装公寓 “ 。你不用关心公寓在哪,只管拎包入住(存数据)。Docker 负责创建、管理和清理。
- 由 Docker 管理的存储空间,存储在 Docker 主机的特定目录下(Linux 通常在
/var/lib/docker/volumes/ - ❌ 依赖主机路径
看冒号 (:) 左边的部分:
- 如果它包含 /、./、../ (在 Linux/macOS) 或 \ (在 Windows),那么它一定是 Bind Mount。 因为你在指定一个明确的、存在于宿主机文件系统上的路径。
- 如果它只是一个简单的字符串,不包含任何路径分隔符,那么它一定是 Volume。 因为你只是在给 Docker 一个名字,让 Docker 自己去管理这个存储空间。
1 2 3 4 5 6 7 8 9 10 11 12 13
| version: '3' services: app: image: myapp volumes: - ./src:/app/src - app-data:/app/data - ./config/app.conf:/app/config/app.conf:ro volumes: app-data:
|
2. 使用技巧
2.1 指定 IP 执行命令
DOCKER_HOST 是 Docker 的一个环境变量,用于指定 Docker 客户端要连接的 Docker 守护进程(daemon)的地址。
1
| DOCKER_HOST=ssh://root@10.133.0.21 docker ps
|
2.2 查看 Docker 实时监控
2.3 告别宿主机
1 2 3
| docker run -it --rm redis:6 redis-cli -h 10.0.114.5 docker run -it --rm redis:7 redis-cli -h 10.0.114.5
|
- 无需本地安装 Redis 客户端,保持本地环境清洁。
- 可以轻松切换不同版本的客户端。
-rm 确保容器用完即删,不占用系统资源。- Docker 容器默认可以访问宿主机能访问的网络。
2.4 多利用 Docker-compose
- 提前拷贝 package 缓存
- 利用数据卷防止 node_modules 被覆盖
- 利用 docker-compose 脚本避免复杂启动参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| FROM node:lts-alpine
RUN apk add --no-cache git openssh-client
RUN npm config set registry https://registry.npmmirror.com
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH
COPY package*.json ./
RUN npm install --production=false hexo-cli && npm install --production=false
COPY . .
EXPOSE 4000
CMD ["hexo", "server"]
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| services: hexo-liuvv: build: context: . dockerfile: Dockerfile image: my-hexo-liuvv container_name: hexo_blog_liuvv ports: - "4000:4000" volumes: - .:/app - /app/node_modules command: sh -c "hexo server"
hexo-deployer: image: my-hexo-liuvv volumes: - .:/app - ~/.ssh:/root/.ssh:ro - ~/.gitconfig:/root/.gitconfig:ro - /app/node_modules command: > sh -c "hexo clean && hexo g -d"
|
2.5 Docker Images 清理
1 2 3 4
| docker images 有很多 none, 会占用磁盘吗?怎么清理
<none> <none> 6038648f7701 9 minutes ago 428MB <none> <none> aeed82987cc4 9 minutes ago 428MB
|
2.6 Docker 容器外更新代码
1 2 3 4 5 6 7 8 9
| docker rm -f dev-ifonly-server docker run -d --restart always --name dev-ifonly-server -p 8899:8888 -p 8890:8890 \ -v /root/scripts/jenkins/jenkins_home/workspace/"$JOB_NAME":/app:ro \ -v /home/ubuntu/.gitconfig:/root/.gitconfig:ro \ -v /home/ubuntu/.git-credentials:/root/.git-credentials:ro \ -v go-pkg-mod:/go/pkg/mod \ -v go-build-cache:/root/.cache/go-build \ --log-driver=fluentd --log-opt fluentd-address=log-collector-internal.ifonlyapp.com:9997 \ -w /app -e GOPRIVATE='git.hoxigames.xyz' -e TZ='Asia/Shanghai' golang:1.21 go run . -f /app/etc/dev/config.yaml
|
最好借助 docker-compose
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| version: '3.8'
services: ifonly-server: container_name: dev-ifonly-server image: golang:1.21 restart: always ports: - "8899:8888" - "8890:8890" volumes: - /root/scripts/jenkins/jenkins_home/workspace/${JOB_NAME}:/app:ro - /home/ubuntu/.gitconfig:/root/.gitconfig:ro - /home/ubuntu/.git-credentials:/root/.git-credentials:ro - go-pkg-mod:/go/pkg/mod - go-build-cache:/root/.cache/go-build working_dir: /app environment: - GOPRIVATE=git.hoxigames.xyz - TZ=Asia/Shanghai logging: driver: fluentd options: fluentd-address: "log-collector-internal.ifonlyapp.com:9997" command: ["go", "run", ".", "-f", "/app/etc/dev/config.yaml"]
volumes: go-pkg-mod: go-build-cache:
|
1 2
| docker-compose up -d docker-compose down
|
2.7 使用非宿主机的 Go
1 2 3 4 5 6 7 8 9 10 11 12
| go build cmd/main.go -o lora-train-platform-server
docker pull golang:1.24.6 docker run --rm \ -v "$(pwd)":/app \ -w /app \ -e GOPROXY=https://goproxy.cn,direct \ golang:1.24.6 \ go build -o lora-train-platform-server cmd/main.go
|
-v "$(pwd)":/app- 这是整个命令的魔法核心!
-v 是 --volume 的缩写,用于将宿主机的文件或目录挂载到容器内部。 "$(pwd)":在 Linux 和 macOS 中,这会自动替换为你的当前工作目录的绝对路径。如果你在 Windows 的 PowerShell 中,"$(pwd)" 也可以工作;如果是在 CMD 中,则需要使用 "%cd%"。:/app:这是将宿主机目录挂载到容器内的 /app 目录。- 效果:这行命令相当于在容器里创建了一个通往你宿主机项目文件夹的 “ 传送门 “。容器内的 Go 编译器就能读到你的
cmd/main.go 以及其他所有源代码文件了。
-w /app-w 是 --workdir 的缩写,它指定了容器内命令执行的工作目录。- 因为我们已经将项目挂载到了
/app,所以我们将工作目录也设置在这里。这样,go build 命令后面的相对路径 cmd/main.go 才能被正确找到。