言成言成啊 | Kit Chen's Blog

Docker与Podman

发布于2025-02-23 01:18:58,更新于2025-03-04 17:40:08,标签:docker  文章会持续修订,转载请注明来源地址:https://meethigher.top/blog

在日常开发中,其实我这里是没有使用 Docker 的,依然是手动安装依赖、配置环境。

但是近期在抄别人的开源项目时,发现 Docker 基本已经成了开发者必备,因此我也特意学习了下,没啥深度,只是记录基础使用。

一、引言

1.1 Docker 是什么?

Docker 是一个开源的容器化平台,它能够让开发者在任何环境下构建、打包和运行应用程序。Docker 通过 容器(Container) 技术,使应用程序及其依赖项能够在不同环境中保持一致性,从而提高部署效率并减少环境差异带来的问题。

Docker 的核心容器引擎(Docker Engine)是开源的,但 Docker 公司围绕它构建了一些 商业化产品(如 Docker Desktop 和 Docker Hub 的高级功能)

简单来说,Docker 就像一个轻量级的虚拟机,但它比传统虚拟机更高效,占用更少资源,同时具备更快的启动速度。

1.2 Docker vs 传统虚拟机

在传统的软件开发和部署过程中,我们通常使用 虚拟机(Virtual Machine,VM) 来运行应用,而 Docker 提供了一种更轻量级的容器化方案。

1.2.1 Docker 与虚拟机对比

对比项Docker 容器传统虚拟机(VM)
架构共享宿主机的操作系统内核每个 VM 运行一个完整的操作系统
启动速度秒级启动(轻量级)分钟级启动(需要引导 OS)
资源占用共享主机资源,占用少每个 VM 需要独立的 CPU、内存
运行效率接近原生性能受限于虚拟化开销,性能较低
环境隔离进程级隔离,共享宿主机内核完全隔离,适用于多种 OS
移植性一次构建,到处运行依赖 VM 具体配置,移植性较差
部署难度轻量级部署,直接运行需要完整安装操作系统,部署复杂
存储管理使用 分层镜像,减少重复存储每个 VM 独立存储,磁盘占用大
适用场景微服务、CI/CD、云原生应用运行不同操作系统、传统 IT 业务

1.2.2 为什么选择 Docker?

Docker 由于 启动快、占用资源少、易于部署,在现代软件开发中越来越流行,特别适用于:

  • 微服务架构:可以将每个服务独立打包成一个容器,方便部署和扩展。
  • 持续集成/持续部署(CI/CD):配合 Jenkins、GitHub Actions,快速构建和发布应用。
  • 云计算和 DevOps:可以轻松迁移、扩展应用,适用于 AWS、Kubernetes 等云平台。

什么时候用传统虚拟机?
如果需要运行 不同操作系统,如 Windows + Linux 环境,或者需要完整的系统级隔离,传统虚拟机仍然是更好的选择。

1.3 Docker 的核心概念

Docker 主要由 镜像(Image)容器(Container)仓库(Registry) 三个核心部分组成:

  • 镜像(Image):应用程序及其依赖的封装,类似于一个模板,用于创建容器。
  • 容器(Container):镜像的运行实例,一个独立的进程,拥有自己的文件系统、网络环境等。
  • 仓库(Registry):用于存储和分发 Docker 镜像,类似于代码仓库,常见的有 Docker Hub、阿里云镜像仓库等。

镜像 → 容器 → 运行应用,这是 Docker 的基本流程,后续章节会详细介绍如何使用 Docker 进行构建、管理和部署应用。

1.4 总结

Docker 和传统虚拟机各有适用场景,但对于大多数现代 Web 应用、微服务架构和 DevOps 流水线,Docker 更加轻量级、高效,能提升开发和运维效率。

Docker 不是要完全取代虚拟机,而是提供了一种更灵活、更高效的应用运行方式!

二、Docker 安装与环境准备

这个安装过程,是以我自己的电脑环境为准。

  • Windows:Windows11
  • Linux:CentOS7

2.1 Windows

官方下载地址:Docker 官网

安装步骤

  1. 下载 Docker Desktop 安装包。
  2. 双击运行安装程序。
  3. 安装完成后,重启计算机。
  4. 启动 Docker Desktop 并检查是否正常运行。

验证安装

1
docker --version

我使用的是VMware16.1版本,安装docker后发现挂起功能无法正常使用了。因此我将Windows上的docker卸载了。

Docker Desktop 需要 Hyper-V 或 WSL2 运行容器。
VMware Workstation Pro 依赖 裸机虚拟化(VT-x / AMD-V),但 Hyper-V 可能会抢占虚拟化权限,导致 VMware 运行变慢或无法启动。

windows 安装完docker, hype-v开启之后,vmware无法使用 - sunny123456 - 博客园

Docker Desktop傻瓜式的包含了许多工具,当然了Docker Desktop仅对个人免费。

2.2 Linux

如果是还在维护的Linux版本,可以参考官网的版本安装 | Docker 文档,而我测试使用的CentOS7已经不再维护了,所以单独记录一下。

2.2.1 安装 Docker

首先,安装docker。创建init.sh,将以下内容复制粘贴进去,然后执行sh init.sh,注册docker-daemon服务。参考二进制文件 | Docker 文档

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
45
46
47
48
49
50
51
52
53
#!/bin/bash
set -e # 遇到任何非零退出码的命令就立即退出

echo "$(date +"%Y-%m-%d %H:%M:%S"): 下载docker..."
curl -L -k -o docker-27.5.1.tgz https://download.docker.com/linux/static/stable/x86_64/docker-27.5.1.tgz
echo "$(date +"%Y-%m-%d %H:%M:%S"): 解压docker..."
tar -zxvf docker-27.5.1.tgz
echo "$(date +"%Y-%m-%d %H:%M:%S"): 添加docker命令..."
cp docker/* /usr/bin/
echo "$(date +"%Y-%m-%d %H:%M:%S"): 创建docker数据目录..."
mkdir -p /data/docker
echo "$(date +"%Y-%m-%d %H:%M:%S"): 创建docker配置文件..."
mkdir -p /etc/docker
cat>/etc/docker/daemon.json<<EOF
{
"builder": {
"gc": {
"defaultKeepStorage": "20GB",
"enabled": true
}
},
"data-root": "/data/docker",
"experimental": false,
"log-driver": "json-file",
"log-opts": {
"max-file": "3",
"max-size": "100m"
},
"registry-mirrors": [
"https://dockerpull.pw",
"https://docker.1ms.run"
]
}
EOF
echo "$(date +"%Y-%m-%d %H:%M:%S"): 注册docker服务..."
cat >/etc/systemd/system/docker.service<<EOF
[Unit]
Description=docker
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/dockerd
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
echo "$(date +"%Y-%m-%d %H:%M:%S"): 启动docker..."
systemctl start docker
echo "$(date +"%Y-%m-%d %H:%M:%S"): 配置docker开机自启动..."
systemctl enable docker
echo "$(date +"%Y-%m-%d %H:%M:%S"): 使用方式: systemctl status docker"
echo "成功"

当脚本执行成功后,运行命令进行镜像拉取、并运行。

1
docker run --rm hello-world

2.2.2 插件 Compose

若有docker compose的需要,还需要再次安装插件。参考插件 | Docker 文档或者docker/compose

创建compose.sh,将以下内容复制粘贴进去,然后执行sh compose.sh,安装插件。

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash
set -e # 遇到任何非零退出码的命令就立即退出

echo "$(date +"%Y-%m-%d %H:%M:%S"): 下载compose..."
curl -L -k -o docker-compose https://github.com/docker/compose/releases/download/v2.32.4/docker-compose-linux-x86_64
echo "$(date +"%Y-%m-%d %H:%M:%S"): 创建compose的lib目录..."
mkdir -p /usr/lib/docker/cli-plugins
echo "$(date +"%Y-%m-%d %H:%M:%S"): 安装docker-compose..."
mv docker-compose /usr/lib/docker/cli-plugins
chmod +x /usr/lib/docker/cli-plugins/docker-compose
echo "成功"

当脚本执行成功后,验证

1
docker compose version

2.2.3 开启ipv4转发

Docker 默认使用 bridge 网络模式,在宿主机上创建一个 docker0 网桥,并给它分配一个子网(如 172.17.0.0/16)。当容器需要访问外网或其他容器时,Linux 需要通过 iptablesnet.ipv4.ip_forward 进行数据包转发

如果 net.ipv4.ip_forward=0,则宿主机不会转发数据包,导致容器无法访问外网或其他容器。

验证是否开启ipv4

1
2
3
4
# 方式一
sysctl net.ipv4.ip_forward
# 方式二
cat /proc/sys/net/ipv4/ip_forward

临时修改,服务器重启后失效

1
2
3
4
# 方式一
sysctl -w net.ipv4.ip_forward=1
# 方式二
echo 1 > /proc/sys/net/ipv4/ip_forward

永久修改

1
2
3
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
# 重新加载内核参数
sysctl -p

三、Docker 核心概念详解

Docker 主要由三大核心概念组成:镜像(Image)、容器(Container)和仓库(Registry)。

3.1 镜像(Image)

镜像是 Docker 的基础,可以理解为一个包含应用及其依赖环境的模板。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 拉取镜像
docker pull <镜像名>:<标签>

# 查看本地已有镜像
docker images

# 删除本地镜像 rmi=rm image
docker rmi <镜像ID/名称>

# 基于运行中的容器创建镜像
# 我在使用postgres容器来创建本地镜像时,发现并没有保留容器内数据,使用docker inspect postgres-container | grep Mounts -A 10才发现即使你没有手动挂载 volume,Docker 也会自动创建一个匿名 volume 并挂载到 /var/lib/postgresql/data 目录。
docker commit <容器ID/名称> <新镜像名>:<标签>

# 无网模式下导出本地镜像
docker save -o myimage.tar 镜像名:标签

# 无网模式下加载镜像
docker load -i /root/myimage.tar

# 基于 Dockerfile 构建镜像
docker build -t <镜像名>:<标签> .

3.2 容器(Container)

容器是镜像的运行实例,包含所有应用运行所需的环境。

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
# 运行容器,并使宿主的时间,ro表示只读模式,防止容器修改宿主时间
docker run -d -v /etc/localtime:/etc/localtime:ro --name mycontainer ubuntu


# 查看正在运行的容器
docker ps

# 查看所有容器(包括已停止的)
docker ps -a

# 进入容器交互模式,以附加进程连接到容器主进程,不影响容器执行
docker exec -it <容器ID/名称> sh
docker exec -it <容器ID/名称> bash

# 以主进程的模式进入容器。此时ctrl+c可能会终止程序
docker attach <容器ID/名称>

# 停止容器
docker stop <容器ID/名称>

# 重启容器
docker restart <容器ID/名称>

# 删除容器
docker rm <容器ID/名称>

# 查看容器日志
docker logs <容器ID/名称>

# 查看容器资源使用情况
docker stats

# 宿主文件复制到容器,反之也可
docker cp 本机文件/目录 容器名:/容器内路径

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]表示创建一个容器,常用OPTIONS说明如下

更全面的命令使用方式,直接docker run --help查阅

  • -d表示后台运行
  • -p 808:8080表示将主机的808端口映射到8080端口
  • --name设置容器名
  • --rm容器运行完后自动删除
  • -v /test:/app/test将主机的/test目录挂载到容器的/app/test目录,除了目录也可以是文件
  • -e "http_proxy=host"设置环境变量

3.3 仓库(Registry)

Docker 镜像存放的地方,可以是 Docker Hub 也可以是私有仓库。

1
2
3
4
5
6
7
8
# 登录 Docker Hub
docker login

# 推送镜像到仓库
docker push <用户名/镜像名>:<标签>

# 从私有仓库拉取镜像
docker pull <私有仓库地址>/<镜像名>:<标签>

3.4 数据管理

针对一些必要的数据,进行数据卷挂载,实现持久化。

1
2
3
4
5
6
7
8
# 数据卷挂载
docker run -d -v /host/path:/container/path --name mycontainer ubuntu

# 查看所有卷
docker volume ls

# 删除数据卷
docker volume rm <卷名>

四、Dockerfile 与自定义镜像

示例代码meethigher/docker-learn: 编写一个Java项目学习Docker使用

4.1 构建 Docker 镜像

Dockerfile 是用于定义自定义镜像的文本文件,包含构建镜像所需的指令。

示例代码meethigher/docker-learn at 构建docker镜像

1
2
3
4
5
6
7
8
9
10
11
# 使用 Java 8 运行时环境 docker pull eclipse-temurin:8-jre-alpine
FROM eclipse-temurin:8-jre-alpine

# 设置容器中的工作目录
WORKDIR /docker-learn

# 复制 JAR 文件到设置的容器目录中
COPY target/docker-learn.jar app.jar

# 运行 Java 应用
CMD ["java", "-jar", "app.jar"]

使用 docker build 命令基于 Dockerfile 构建镜像。

1
2
3
4
5
# 格式。如果不使用标签,默认是latest
docker build -t <镜像名>:<标签> <构建上下文>

# -t指定镜像名。.表示当前目录(目录应是Dockerfile所在目录)
docker build -t docker-learn .

4.2 多阶段构建优化 Docker 镜像

使用多阶段构建可以减少最终镜像的大小,它仅保留运行时所需的文件,而不会把构建过程中产生的无关文件带入最终镜像,提高构建效率。

示例代码meethigher/docker-learn at 多阶段构建docker镜像

1
2
3
4
5
6
7
8
9
10
11
# 第一阶段:构建阶段
FROM maven:3.6.3-openjdk-8 AS builder
WORKDIR /app
COPY . .
RUN mvn clean package -DskipTests

# 第二阶段:运行阶段。将第一阶段的构建产物复制到第二阶段中
FROM eclipse-temurin:8-jre-alpine
WORKDIR /app
COPY --from=builder /app/target/docker-learn.jar app.jar
CMD ["java", "-jar", "app.jar"]

执行构建命令后如图

4.3 推送镜像到 Docker Hub/私有仓库

1
2
3
4
5
6
7
8
# 登录 Docker Hub
docker login

# 给镜像打标签(格式:仓库名/镜像名:标签)
docker tag my-nginx your_dockerhub_username/my-nginx:v1

# 推送到 Docker Hub
docker push your_dockerhub_username/my-nginx:v1

五、Docker Compose(多容器管理)

5.1 什么是 Docker Compose?

Docker Compose 允许使用 docker-compose.yml 文件来定义和管理多个容器。

5.2 使用 Docker Compose 启动多容器

示例代码meethigher/docker-learn at docker-compose

以下是一个 docker-compose.yml 文件示例,定义了 app和 db 两个服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
services:
app:
build: .
container_name: java_app
depends_on:
- db
environment:
DB_URL: jdbc:postgresql://db:5432/mydatabase
DB_USER: myuser
DB_PASSWORD: mypassword
ports:
- "8080:8080"

db:
image: postgres:15
container_name: postgres_db
restart: always
environment:
POSTGRES_DB: mydatabase
POSTGRES_USER: myuser
POSTGRES_PASSWORD: mypassword
ports:
- "5432:5432"

启动容器

1
2
3
4
5
6
7
8
# 在当前目录下启动所有服务 -d表示后台 --build表示重新构建
docker compose up -d

# 查看运行中的容器
docker compose ps

# 停止并删除所有容器
docker compose down

日志与调试

1
2
3
4
5
# 查看所有服务的日志
docker compose logs -f

# 查看特定服务的日志
docker compose logs -f nginx

六、Docker 替代品之 Podman

6.1 Podman 简介

Podman(Pod Manager)是一个无守护进程的容器管理工具,功能类似 Docker,主要用于管理 OCI(Open Container Initiative)容器。与 Docker 不同,Podman 不需要后台守护进程(daemon),并且支持 rootless 模式,使得容器运行更加安全。

Podman vs Docker:

特性DockerPodman
守护进程需要 Docker Daemon无需守护进程
权限管理需要 root 或 sudo可 rootless 运行
兼容 Docker CLI✅(几乎 100% 兼容)
适用于生产环境✅(更安全)

6.2 为什么选择 Podman?

Podman 具有以下优势:

  1. 无守护进程(Daemonless):不像 Docker 依赖 dockerd 守护进程,Podman 直接运行容器,使得系统更加安全稳定。
  2. Rootless 模式:Podman 允许普通用户运行容器,而不需要 root 权限,降低安全风险。
  3. 兼容 Docker:Podman 的 CLI 命令与 Docker 几乎一致。
  4. Pod 支持:Podman 内置 Pod 概念,能够更好地支持 Kubernetes 生态。
  5. 更轻量:相比 Docker,Podman 不依赖后台进程,资源占用更少。
发布:2025-02-23 01:18:58
修改:2025-03-04 17:40:08
链接:https://meethigher.top/blog/2025/docker-learn/
标签:docker 
付款码 打赏 分享
Shift+Ctrl+1 可控制工具栏