1. Docker核心概念速览
- 镜像:一个只读的模板,包含了运行应用所需的所有内容(操作系统、库、代码、环境变量等)。可以把它看作是面向对象编程中的"类"。
- 容器:镜像的一个运行实例。它是可读写的,包含了应用运行时的进程。可以看作是"对象"。
- Dockerfile:一个文本文件,包含了构建Docker镜像所需的所有指令。这是容器化的"蓝图"。
2. 安装Docker
卸载旧版本
bash
sudo apt-get remove docker docker-engine docker.io containerd runc
Docker安装方式【二选一】
1. 使用Docker存储库安装
更新 apt 包索引并安装相关软件包以允许 apt 通过 HTTPS 使用 docker 存储库:
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg lsb-release
添加 Docker 的官方 GPG 密钥:
bash
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
设置存储库:
bash
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee -a /etc/apt/sources.list.d/docker.list > /dev/null
2. 使用阿里安装
因为官方下架了dockerhub的镜像,更换一个阿里的镜像源。
更新 apt 包索引并安装相关软件包以允许 apt 通过 HTTPS 下载安装:
bash
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg lsb-release
添加阿里云的Docker GPG密钥
bash
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
添加阿里云的Docker源
bash
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
安装 Docker engine
bash
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
验证安装完成
bash
sudo docker -v
# 打印出版本号
Docker version 29.0.4, build 3247a5a
3. 配置 Docker 国内镜像源
用于解决国内访问 Docker Hub 网络问题。
- 创建或编辑 Docker 配置文件
Docker 守护进程的配置文件通常位于/etc/docker/daemon.json。如果这个文件不存在,就创建它。
bash
sudo vim /etc/docker/daemon.json
- 添加镜像源配置
将以下内容复制到daemon.json文件中。
json
{
"registry-mirrors": [
"https://docker.1ms.run",
"https://docker.xuanyuan.me"
]
}
- 重启 Docker 服务
配置文件修改后,需要重启 Docker 来让配置生效。
bash
sudo systemctl restart docker
- 验证配置
可以通过info命令查看镜像源是否配置成功。
bash
sudo docker info | grep -A 10 "Registry Mirrors"
如果看到刚刚配置的镜像源地址,就说明成功了。
4. 创建镜像
假设项目结构如下:
/home/ubuntu/C_C++/demo/
├── demo.c
└── Dockerfile
demo.c 的内容:
c
#include <stdio.h>
int main() {
printf("Hello from a containerized C application!\n");
return 0;
}
编写 Dockerfile
在 demo 目录下,创建一个名为 Dockerfile 的文件,内容如下:
dockerfile
# Stage 1: Build Stage (构建阶段)
# 使用一个包含GCC编译器的官方镜像作为基础镜像
FROM gcc:9.4 AS builder
# 设置工作目录
WORKDIR /usr/src/app
# 复制当前目录下的所有文件到工作目录
COPY . .
# 编译C程序
# -o demo 指定输出文件名为 demo
RUN gcc -o demo demo.c
# Stage 2: Runtime Stage (运行阶段)
# 使用一个最小化的镜像作为最终运行环境
FROM debian:buster-slim
# 设置工作目录
WORKDIR /app
# 从构建阶段复制编译好的可执行文件到当前镜像
# --from=builder 指定从上一个名为 builder 的阶段复制
COPY --from=builder /usr/src/app/demo .
# 容器启动时执行的命令
CMD ["./demo"]
Dockerfile 指令解析
-
FROM <image>: 指定基础镜像。gcc:9.4提供了编译环境,debian:buster-slim是一个非常小的运行环境。 -
WORKDIR <dir>: 设置工作目录,后续的COPY,RUN,CMD都会在此目录下执行。 -
COPY <src> <dest>: 将文件从宿主机复制到镜像中。 -
RUN <command>: 在镜像构建过程中执行命令(比如编译)。 -
CMD ["executable", "param1", "param2"]: 指定容器启动时默认执行的命令。
多阶段构建
在 Dockerfile 中,每一个 FROM 指令不仅仅是引入一个基础镜像,它实际上是开启了一个全新的构建阶段。当 Dockerfile 执行完毕,Docker 只会把最后一个 FROM 阶段生成的内容打上标签,作为最终镜像。
第一阶段用大体积的编译镜像生成可执行文件,第二阶段只把最终的可执行文件复制到一个干净、小巧的运行镜像中。
构建镜像
在 demo 目录下,打开终端执行以下命令:
bash
# -t demo-app 给我们的镜像打一个标签,便于识别
# . 表示构建上下文是当前目录
sudo docker build -t demo-app .
查看镜像
运行以下命令就能看到创建的镜像。
bash
sudo docker images
运行容器
bash
# --rm 容器退出后自动删除
sudo docker run --rm demo-app
输出:
bash
Hello from a containerized C application!
查看所有容器(包括停止的)
bash
sudo docker ps -a
删除所有停止的容器
bash
sudo docker container prune
删除指定的镜像
bash
sudo docker rmi <image_id_or_name>
删除所有未使用的镜像
bash
sudo docker system prune -a
5. 分离开发环境和运行环境
- 开发环境 :一个包含所有开发工具(如
gcc,gdb,make等)的容器,用于编码、编译、调试。 - 运行环境:一个精简的、只包含运行依赖的容器,用于部署和运行最终产品。
前文的 Dockerfile 有一个痛点:每次修改 demo.c 里的代码,都必须重新 docker build 一次。因为c-demo 里面根本没有开发工具,相当于精简版操作系统 + 程序,只能运行程序。
在开发阶段,不需要每次都 Build,可以创建一个 GCC 环境作为开发环境,并把宿主机的文件夹映射到容器里。实现在本地改代码,Docker 里编译程序,而且这个程序直接出现当前目录下。
创建开发容器
第一种情况:一键编译并运行
第一次运行会去 Docker Hub执行 docker pull gcc:9.4下载镜像。
bash
# 第一部分:Docker 的配置
# 使用官方的 gcc 镜像启动一个开发容器
# -v $(pwd):/src 将宿主机的代码目录挂载到容器的 /src 目录
# -w /src 设置容器内的工作目录,启动后,直接进入
# gcc:9.4 指定gcc版本镜像
# 第二部分:容器内的指令
# gcc -o demo demo.c
# 第三部分:宿主机的指令
# && 如果前面的 Docker 命令成功执行(编译没报错),那么就执行后面的命令
sudo docker run -it --rm -v $(pwd):/src -w /src gcc:9.4 gcc -o demo demo.c && ./demo
第二种情况:在开发容器内工作
启动开发容器
bash
# -it: i = interactive (保持STDIN开放), t = allocate a pseudo-TTY (分配一个伪终端)
# /bin/bash: 覆盖Dockerfile中的CMD,启动一个bash shell
sudo docker run -it --rm -v $(pwd):/src -w /src gcc:9.4 /bin/bash
在开发容器内工作
bash
# 你会看到提示符,比如:
root@2f3a4b5c6d7e:/src#
# 验证 gcc 是否存在
gcc --version
# 编译代码
gcc -o demo demo.c
# 运行它
./demo
6. 去掉sudo
在使用非root用户输docker命令需要sudo,在 Linux 中,可以把当前用户加入 docker 用户组,这样就不需要 sudo 了。
操作步骤(仅需做一次):
- 创建 docker 组(如果已存在则跳过):
bash
sudo groupadd docker
- 把当前用户加入组:
bash
sudo usermod -aG docker $USER
- 注销并重新登录,或者执行以下命令让组权限立即生效:
bash
newgrp docker