Docker基础操作

整合一遍Docker相关的操作。

一、介绍

Docker 是一款开源的应用容器平台。主要概念是镜像、容器、仓库。

生命周期

1
创建(create)→ 启动(start)→ 运行(running)→ 停止(stop)→ 重启(restart)→ 删除(rm

二、安装

需要内核高于3.10版本。

2.1 在线脚本安装

官网安装脚本

清华源在线安装脚本

国内通用镜像源

1
2
3
4
5
export DOWNLOAD_URL="https://mirrors.tuna.tsinghua.edu.cn/docker-ce"
# 如您使用 curl
curl -fsSL https://raw.githubusercontent.com/docker/docker-install/master/install.sh | sh
# 如您使用 wget
wget -O- https://raw.githubusercontent.com/docker/docker-install/master/install.sh | sh

注意:本质就是设置 DOWNLOAD_URL,镜像源有 docker-ce 的都可以。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 阿里云
export DOWNLOAD_URL="https://mirrors.aliyun.com/docker-ce"

# 网易云
export DOWNLOAD_URL="https://mirrors.163.com/docker-ce"

# 中国科学技术大学
export DOWNLOAD_URL="https://mirrors.ustc.edu.cn/docker-ce"

# 南阳理工学院
export DOWNLOAD_URL="https://mirror.nyist.edu.cn/docker-ce"

# 搜狐
export DOWNLOAD_URL="https://mirrors.sohu.com/docker-ce"

2.2 yum安装

  1. 卸载旧版本
1
2
3
4
5
6
7
8
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
  1. 安装依赖
1
yum install -y yum-utils device-mapper-persistent-data lvm2
  1. 配置docker源,(使用阿里云)
1
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
  1. 安装最新版本Docker CE(社区版)
1
yum install -y docker-ce docker-ce-cli containerd.io

安装指定版本Docker CE(社区版)

1
yum install -y docker-ce-20.10.24 docker-ce-cli-20.10.24 containerd.io-1.6.33
  1. 验证
1
2
docker --version
docker info
  1. 开启自启
1
2
systemctl start docker
systemctl enable docker

2.3 Docker官方维护的yum

  • 使用清华源替代文件
1
2
curl -o /etc/yum.repos.d/docker-ce.repo https://download.docker.com/linux/centos/docker-ce.repo
sed -i 's+download.docker.com+mirrors.tuna.tsinghua.edu.cn/docker-ce+' /etc/yum.repos.d/docker-ce.repo

1
2
3
yum install -y yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sed -i 's+https://download.docker.com+https://mirrors.tuna.tsinghua.edu.cn/docker-ce+' /etc/yum.repos.d/docker-ce.repo
  1. 卸载
1
2
3
4
5
6
7
8
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
  1. 安装最新版
1
yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
  1. 查看支持的版本
1
yum list docker-ce --showduplicates
  1. 安装指定的版本
1
2
3
yum -y install docker-ce-20.10.24 docker-ce-cli-20.10.24
yum -y install bash-completion
source /usr/share/bash-completion/bash_completion
  1. 打包离线版本
1
vim /etc/yum.conf
1
keepcache=1
1
cd ~ && mkdir docker-rpm-20_10_24 && find /var/cache/yum -name "*.rpm" |xargs mv -t docker-rpm-20_10_24/
  1. 本地安装
1
yum localinstall *.rpm

2.4 docker-compose安装

20.10.24版本没有自带compose

  • 下载
1
curl -L "https://github.com/docker/compose/releases/download/v2.20.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
  • 加速下载
1
curl -L "https://gh.bravexist.cn/https://github.com/docker/compose/releases/download/v2.20.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
  • 添加执行权限
1
chmod +x /usr/local/bin/docker-compose
  • 创建软链接(可选)
1
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
  • 验证安装
1
docker-compose --version

三、配置镜像源

配置镜像源主要为了能拉取镜像。有时也可以直接使用代理。

1
2
mkdir -p /etc/docker
vim /etc/docker/daemon.json
1
2
3
{
"registry-mirrors": ["https://hub.bravexist.cn"]
}
1
2
sudo systemctl daemon-reload
sudo systemctl restart docker

验证

1
docker info | grep -A 1 "Registry Mirrors"
1
docker pull hello-world

直接使用代理。

1
2
mkdir /usr/lib/systemd/system/docker.service.d
vi /usr/lib/systemd/system/docker.service.d/http-proxy.conf
1
2
3
4
[Service]
Environment="HTTP_PROXY=http://127.0.0.1:7897"
Environment="HTTPS_PROXY=http://127.0.0.1:7897"
Environment="NO_PROXY=localhost,127.0.0.1,.example.com"
1
2
sudo systemctl daemon-reload
sudo systemctl restart docker
1
systemctl show docker --property Environment
1
docker pull hello-world

四、镜像

  1. 拉取镜像
1
docker pull ubuntu
  1. 查看镜像
1
docker images
1
docker image ls
  1. 删除镜像
1
docker rmi 镜像名称或镜像ID
1
docker image rm 镜像名称或镜像ID
  1. 保存镜像
1
docker save 镜像名称 -o 镜像的tar包
  1. 导入镜像
1
docker load -i 镜像的tar包
  1. 打标签
1
docker tag 源镜像:标签 目标镜像:标签
  1. 生成导出所有的镜像命令
1
docker images|awk 'NR>1{print "docker save",$1":"$2,"-o",$1"_"$2".tar"}'
1
docker images|awk 'NR>1{print "docker save",$1":"$2,"-o",$1"_"$2".tar"}' |bash

注意

新版本显示格式稍有区别。

1
docker images |awk 'NR>1{print "docker save",$1,"-o",$1".tar"}'
1
docker images |awk 'NR>1{print "docker save",$1,"-o",$1".tar"}'|bash

通用导出命令

1
2
3
docker images --format '{{.Repository}} {{.Tag}}' | \
awk '{f=$1"_"$2".tar";gsub("/","_",f);print $1":"$2, f}' | \
xargs -n2 sh -c 'docker save "$0" -o "$1"'

导入

1
for image in *.tar; do docker load -i "$image"; done
  1. 查看镜像的详细信息
1
docker image inspect 镜像名称
  1. 清理无效的镜像(名称、标签都为none)
1
docker image prune -a
  1. 构建镜像
1
docker build -t 镜像名称 .
  • . 代表 Dockerfile 文件在当前目录
  1. 搜索镜像
1
docker search 镜像名称

五、容器

  1. 启动容器,以 nginx 为例。
1
docker run -itd -p 宿主机端口:容器内部端口 --name 实例名称 镜像名称:版本号 终端名称
1
docker run -d -p 90:80 --name "qk_nginx" nginx:alpine
  • -d 后台运行

  • -p 端口映射,需要开启内核转发功能。

    1
    vim /etc/sysctl.conf
    1
    net.ipv4.ip_forward = 1
  • alpine 这个版本的镜像体积小

  • -i 进入交互模式,-it 经常配合使用,还需要指定 shell

  • -t 分配一个终端

  • --name 给容器指定名称,不设置会随机起名字

  1. 查看运行中的容器
1
docker ps
  1. 查看所有的容器
1
docker ps -a
  1. 进入容器内部
1
docker exec -it 容器名称或容器ID 执行的命令
  1. 查看容器日志
1
docker logs 容器名称或容器ID
  1. 实时查看容器日志
1
docker logs -f 容器名称或容器ID
  1. 停止容器
1
docker stop 容器名称或容器ID
  1. 删除停止的容器(高风险操作
1
docker rm 容器名称或容器ID
  1. 重启容器
1
docker restart 容器名称或容器ID
  1. 删除运行中的容器(高风险操作
1
docker rm -f 容器名称或容器ID
  1. 拷贝文件
1
docker cp 宿主机文件 容器名称:容器内部文件
1
docker cp 容器名称:容器内部文件 宿主机文件

六、构建镜像

构建镜像会使用 Dockerfile 文件。

6.1 核心指令

指令 作用 实例
FROM 指定基础镜像(必须是第一条指令) FROM centos:7
MAINTAINER 弃用)维护者信息 MAINTAINER devops <admin@example.com>
LABEL 全能的键值对 LABEL maintainer="ZhangSan <zhangsan@example.com>"
RUN 构建时执行的命令(如安装软件) RUN rm -rf /etc/yum.repos.d/*
COPY 复制主机文件、目录到容器 COPY index.html /usr/share/nginx/html
ADD 类似 COPY ,支持解压压缩包、下载远程文件 ADD app.tar.gz /opt
WORKDIR 设置容器工作目录(后续指令的执行目录) WORKDIR /usr/share/nginx
EXPOSE 生命容器暴露的端口(仅文档说明,不会自动映射) EXPOSE 80
CMD 容器启动时执行的命令(可被 docker run 覆盖) CMD ["nginx", "-g", "daemon off;"]
ENTRYPOINT 容器启动时的入口命令(不可被覆盖,需结合 --entrypoint 参数) ENTRYPOINT ["nginx"],默认是/bin/sh -c
ENV 设置环境变量 ENV NGINX_VERSION=1.24

6.2 构建镜像

1
docker build -t 新镜像的名称:版本号 .

6.3 Dockerfile 案例

NodeJS

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# =========================================================
# 🏗️ 第一阶段:构建层 (Builder)
# 目标:安装依赖、编译源码。这一层可以很重,反正最后会丢掉。
# =========================================================

# 1. 使用 ARG 定义版本,方便通过 --build-arg 动态修改
ARG NODE_VERSION=18
FROM node:${NODE_VERSION}-alpine AS builder

# 2. 设置国内源 (可选,如果构建慢的话)
# RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories

# 3. 安装必要的系统编译工具 (Python, Make, GCC 等)
# 很多 npm 包需要编译原生模块,Alpine 默认是不带的
RUN apk add --no-cache libc6-compat python3 make g++

WORKDIR /app

# [关键技巧] 4. 单独复制依赖描述文件
# 为什么?因为只要 package.json 没变,Docker 就会利用缓存,跳过 npm install
# 如果你写 COPY . . 那么每次改代码都会导致重新安装依赖!
COPY package*.json ./

# 5. 安装依赖 (使用 ci 也就是 clean install,比 install 更快更稳)
RUN npm ci

# 6. 复制所有源代码
COPY . .

# 7. 开始编译 (如果是 TS 或需要构建)
RUN npm run build

# =========================================================
# 🚀 第二阶段:运行层 (Runner)
# 目标:只包含运行时文件,极其精简,安全
# =========================================================

FROM node:${NODE_VERSION}-alpine AS runner

# 8. 添加 OCI 标准 Label (让镜像看起来很专业)
LABEL org.opencontainers.image.authors="你的名字 <email@example.com>"
LABEL org.opencontainers.image.source="https://github.com/你的仓库"

WORKDIR /app

# 9. 环境变量设置 (ENV 会落盘,不要放密码!)
ENV NODE_ENV=production
ENV PORT=3000

# 10. 创建非 root 用户 (为了安全,永远不要用 root 跑应用)
# Alpine 的 node 镜像通常自带一个 'node' 用户,这里演示如何新建
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001

# 11. 从构建层“偷”走你需要的东西
# 比如 node_modules (只含生产依赖) 和 构建好的 dist 目录
COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
COPY --from=builder --chown=nodejs:nodejs /app/package.json ./package.json

# [演示 ADD] 如果你需要从远程下载配置文件(比如公共配置),可以用 ADD
# ADD https://example.com/config.json ./config/config.json

# 12. 切换到非 root 用户
USER nodejs

# 13. 声明端口 (仅作为文档说明,不具备强制性)
EXPOSE 3000

# 14. 启动命令
CMD ["node", "dist/main.js"]

静态网站

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
# =========================================================
# 🏗️ 第一阶段:生成静态文件
# =========================================================
FROM node:18-alpine AS builder

WORKDIR /app

# 利用缓存机制安装依赖
COPY package*.json ./
RUN npm install --registry=https://registry.npmmirror.com

# 复制源码并生成 (Hexo generate)
COPY . .
RUN npm run build
# 此时,/app/public 目录下就是生成的全套 HTML/CSS/JS

# =========================================================
# 🚀 第二阶段:Nginx 托管
# =========================================================
FROM nginx:alpine AS runner

LABEL maintainer="Docker爱好者"

# 1. 替换 Nginx 默认配置 (你需要自己在项目里准备一个 nginx.conf)
# 这一步能解决 404 问题和开启 Gzip 压缩
COPY nginx.conf /etc/nginx/conf.d/default.conf

# 2. 从上一阶段把生成的 HTML 复制到 Nginx 默认目录
COPY --from=builder /app/public /usr/share/nginx/html

# 3. 设置时区 (可选,看日志方便)
RUN apk add --no-cache tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone

EXPOSE 80

# Nginx 默认 CMD 就是启动服务,所以这里其实可以不写,但写上也无妨
CMD ["nginx", "-g", "daemon off;"]

6.4 优化 Dockerfile

  • 合并 RUN 指令,减少镜像层数
  • 清理yum缓存
  • 使用轻量级基础镜像(如 alpine

七、网络及数据持久化

7.1 网络模式

模式 特点 使用场景
bridge(桥接) 默认模式,容器连接到 docker0 网桥,与主机互通,荣期间通过网桥通信 大多数单机应用
host(主机) 容器共享主机网络命名空间,无端口映射,性能最高 网络性能要求高的应用
container 共享另一个容器的网络命名空间 多容器协同(如应用 + 数据库)
none 容器无网络接口,仅本地回环 无需网络的离线应用

使用 -net--network 指定。如:

  • -net=host
  • -net=container(容器名或ID)
  • -net=bridge

7.2 网络相关命令

  1. 查看网络
1
docker nerwork ls
  1. 创建自定义桥接网络
1
docker network create 网络名称
  1. 查看网络详情
1
docker network inspect 网络名称
  1. 启动时加入网络
1
docker run -d --network 网络名称 镜像名称

7.3 数据持久化

  1. 创建数据卷
1
docker volume create 数据卷名称
  1. 查看数据卷
1
docker volume ls
  1. 查看数据卷详情(默认路径在 /var/lib/docker/volume
1
docker volume inspect 数据卷名称
  1. 数据卷挂载
1
docker run -d -v 数据卷:容器内目录 镜像名称
  1. 绑定挂载
1
docker run -d -v 本地目录:容器内目录 镜像名称
  1. 删除数据卷
1
docker volume rm 数据卷名称

八、Docker Compose

容器编排技术,使用 yaml 文件来定多容器应用的服务。

yaml 文件常命名为 docker-compose.yamlcompose.yaml.ymal.yml 也可以混用。

8.1 安装(旧版本)

旧版本需要单独安装 docker-compose 命令,新版本 docker 自带子命令 compose

1
curl -L "https://github.com/docker/compose/releases/download/v2.20.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
  • 添加执行权限
1
chmod +x /usr/local/bin/docker-compose
  • 创建软链接(可选)
1
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
  • 验证安装
1
docker-compose --version

8.2 相关操作

核心结构

1
2
3
4
5
6
7
8
9
10
version: "3.8"  # Compose 文件版本
services: # 服务列表
service1: # 服务名
image: # 镜像名
ports: # 端口映射
volumes: # 数据卷挂载
environment: # 环境变量
networks: # 网络配置
networks: # 自定义网络
volumes: # 自定义数据卷

启动

1
docker compose up -d

停止

1
docker compose down

重启

1
docker compose restart 服务名

进入某个服务

1
docker compose exec 服务名 /bin/bash

构建自定义镜像

1
docker compose build

8.3 案例

案例一,wordpress

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
version: "3.8"
services:
# MySQL 服务
db:
image: mysql:5.7
volumes:
- mysql-data:/var/lib/mysql
restart: always # 容器异常自动重启
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: wordpress
MYSQL_USER: wp_user
MYSQL_PASSWORD: wp_pass
networks:
- wp-network
# WordPress 服务
wordpress:
depends_on: # 依赖 db 服务,先启动 db
- db
image: wordpress:latest
volumes:
- wp-data:/var/www/html
ports:
- "8080:80"
restart: always
environment:
WORDPRESS_DB_HOST: db:3306 # 连接 db 服务的 3306 端口
WORDPRESS_DB_USER: wp_user
WORDPRESS_DB_PASSWORD: wp_pass
WORDPRESS_DB_NAME: wordpress
networks:
- wp-network
# 自定义数据卷
volumes:
mysql-data:
wp-data:
# 自定义网络
networks:
wp-network:

案例二,前后端分离应用

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
version: "3.8"
services:
# Redis 服务
redis:
image: redis:6.2
ports:
- "6379:6379"
volumes:
- redis-data:/data
networks:
- app-network
# 后端服务(假设已有 springboot-app:v1 镜像)
backend:
image: springboot-app:v1
ports:
- "8080:8080"
environment:
SPRING_REDIS_HOST: redis
SPRING_REDIS_PORT: 6379
depends_on:
- redis
networks:
- app-network
# 前端 Nginx 服务
frontend:
image: nginx:1.24
ports:
- "80:80"
volumes:
- ./frontend:/usr/share/nginx/html
- ./nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- backend
networks:
- app-network
volumes:
redis-data:
networks:

九、私有仓库 registry

registry 是 Docker官方的私有仓库。

  1. 运行私有仓库。
1
docker run --name "pri_registry" --restart=always -d -p 5000:5000 registry
  1. 验证是否运行成功
1
curl -I 127.0.0.1:5000
  1. 放行防火墙
1
2
firewall-cmd --permanent --add-port=5000/tcp
firewall-cmd --reload
  1. 上传下载,测试功能是否正常
1
docker pull busybox
1
2
3
# docker tag busybox 私有仓库IP:端口/busybox
# 地址/路径/名字:版本
docker tag busybox 192.168.10.18:5000/busybox
1
2
docker push 192.168.10.18:5000/busybox
docker pull 192.168.10.18:5000/busybox

默认使用 https ,不会成功。

1
vim /etc/docker/daemon.json
1
2
3
4
{
"registry-mirrors": ["https://hub.bravexist.cn"],
"insecure-registries": ["192.168.10.18:5000"]
}
1
2
sudo systemctl daemon-reload
sudo systemctl restart docker

十、Web-UI

10.1

很旧的一个Web-UI,cli 也能看的一些内容。

1
docker pull uifd/ui-for-docker
1
docker run -it -d --name docker-web -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock uifd/ui-for-docker 
1
2
firewall-cmd --permanent --add-port=9000/tcp
firewall-cmd --reload

10.2 portainer-ce

1
docker pull portainer/portainer-ce
1
docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest
1
2
firewall-cmd --permanent --add-port=8000/tcp --add-port=9443/tcp
firewall-cmd --reload
1
https://192.168.10.18:9443

中文版(非官方版本)

1
docker pull 6053537/portainer-ce
1
# docker run -d --restart=always --name="portainer" -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock 6053537/portainer-ce
1
2
firewall-cmd --permanent --add-port=9000/tcp
firewall-cmd --reload
1
http://192.168.10.18:9000

10.3 dockge

uptime-kuma 作者的产品,使用 docker-compose 部署。可以手动修改版本。

方便的编写 compose 可视化。

1
2
3
4
5
6
7
8
9
10
11
12
# Create directories that store your stacks and stores Dockge's stack
mkdir -p /opt/stacks /opt/dockge
cd /opt/dockge

# Download the compose.yaml
curl https://raw.githubusercontent.com/louislam/dockge/master/compose.yaml --output compose.yaml

# Start the server
docker compose up -d

# If you are using docker-compose V1 or Podman
# docker-compose up -d
1
2
firewall-cmd --permanent --add-port=5001/tcp
firewall-cmd --reload
1
http://192.168.10.18:5001

10.4 yacht

1
2
docker volume create yacht
docker run -d -p 8000:8000 -v /var/run/docker.sock:/var/run/docker.sock -v yacht:/config --name yacht --restart unless-stopped selfhostedpro/yacht
1
2
admin@yacht.local
pass

10.5 1panel

….

十一、Harbor镜像仓库

官网仓库

  1. 下载
1
wget https://github.com/goharbor/harbor/releases/download/v2.14.1/harbor-offline-installer-v2.14.1.tgz
  1. 解压
1
tar xf harbor-offline-installer-v2.14.1.tgz -C /usr/local/
  1. 编辑配置文件,注释掉https 相关的内容。
1
2
3
cd /usr/local/harbor
cp harbor.yml.tmpl harbor.yml
vim harbor.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
hostname = 192.168.1.200 //修改IP地址
# HTTPS配置
# https related config
https:
# https port for harbor, default is 443
port: 443
# The path of cert and key files for nginx
certificate: /your/certificate/path
private_key: /your/private/key/path
# enable strong ssl ciphers (default: false)
# strong_ssl_ciphers: false

# 默认密码,
harbor_admin_password: Harbor@123

# 存储配置
data_volume: /data
1
./install.sh

默认不带杀毒,可选项

1
./install.sh --with-trivy
  1. 访问
1
http://192.168.10.18/
1
2
admin
Harbor12345
  1. 登录
1
vim /etc/docker/daemon.json
1
2
3
4
{
"registry-mirrors": ["https://hub.bravexist.cn"],
"insecure-registries": ["192.168.10.18:5000"]
}
1
2
sudo systemctl daemon-reload
sudo systemctl restart docker
1
docker login 192.168.10.18:80
  1. pushpull
1
docker tag hello-world 192.168.10.18:80/system/hello-world
1
docker push 192.168.10.18:80/system/hello-world:latest
1
docker pull 192.168.10.18:80/system/hello-world:latest

十二、问题

  1. docker内无法解析域名,导致无法安装软件包
1
sudo vim /etc/docker/daemon.json
1
2
3
4
5
6
7
{
"dns": [
"223.5.5.5",
"114.114.114.114",
"8.8.8.8"
]
}
1
2
sudo systemctl daemon-reload
sudo systemctl restart docker
  1. Harbor 不支持扫描,安装时携带扫描器
1
./install.sh --with-trivy