Docker 总结

镜像

查看镜像

1
docker images

构建镜像

1
2
# 镜像名: ubuntu-with-vi
docker build -t ubuntu-with-vi
特定镜像名 由 repository:tag 构成 注意:tag 为 latest 并无特殊含义,仅仅是 未指明 镜像 tag 时,Docker 会使用 默认值 latest 而已 尽管 Docker Hub 上很多 repository 将 latest 作为 最新稳定版本 别名,但这仅仅是约定,非强制规定
1
docker build -t yiyungent/uhub .
注意:repository name must be lowercase 镜像名必须小写 最后有个 点 . 表示从当前路径找 Dockerfile 文件进行构建

重命名镜像

1
2
3
4
docker tag oldImageName [username]/xxx:tag

# 举例
docker tag ubuntu yiyungent/my-ubuntu:v1
[username]/ 部分非必需,如果要上传到 Docker Hub,repository 则需有用户名部分

上传镜像

1
docker push yiyungent/my-ubuntu:v1

下载镜像

1
docker pull yiyungent/my-ubuntu:v1

显示镜像构建历史

1
docker history my-ubuntu

从容器创建新镜像

1
docker commit # TODO: 待添加参数

从 Dockerfile 构建镜像

1
docker build

给镜像打 tag

1
docker tag my-ubuntu yiyungent/my-ubuntu:v1

删除 Docker host 中的镜像

1
docker rmi my-ubuntu

搜索 Docker Hub 中的镜像

1
docker search ubuntu
容器

查看容器

1
2
3
4
5
6
7
# 以下两条等价:查看 正在运行 的容器
docker ps
docker container ls

# 以下两条等价:查看 所有状态 的容器
docker ps -a
docker container ls -a
容器的 生命周期 依赖于 启动时执行的命令,只要该命令不结束,容器就不会退出

创建并启动容器

1
docker run
--name 指定容器名称(NAMES),不指定 Docker 会自动给容器分配名称 -d 以后台方式启动容器

进入容器

docker attach

1
2
# attach 到 容器启动命令 的终端
docker attach <container>

docker exec

1
docker exec -it <container> bash|sh
互传文件 参考: docker cp | Docker Documentation

容器->宿主机

1
docker cp container_id:<docker容器内的路径> <本地保存文件的路径>
1
docker cp 10704c9eb7bb:/root/test.text /home/vagrant/test.txt
注意: 上方此种写法, 必须要求 /home/vagrant/test.txt 已存在, 然后会被覆盖

宿主机->容器

1
docker cp 本地文件的路径 container_id:<docker容器内的路径>
1
docker cp  /home/vagrant/test.txt 10704c9eb7bb:/root/test.text

补充

1
2
3
docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH

docker cp [OPTIONS] SRC_PATH CONTAINER:DEST_PATH
假设路径分隔符为/,第一个参数为SRC_PATH,第二个参数为DEST_PATH,行为如下: SRC_PATH指定一个文件 DEST_PATH不存在 该文件被保存到创建的文件中DEST_PATH DEST_PATH不存在并以/ 错误条件:目标目录必须存在。 DEST_PATH存在并且是一个文件 目标被源文件的内容覆盖 DEST_PATH存在并且是一个目录 使用来自的基本名称将文件复制到此目录中 SRC_PATH SRC_PATH指定目录 DEST_PATH不存在 DEST_PATH被创建为一个目录,并且源目录的内容被复制到这个目录中 DEST_PATH存在并且是一个文件 错误情况:无法将目录复制到文件 DEST_PATH存在并且是一个目录 SRC_PATH不以/.(即:斜线后跟) 结尾 源目录复制到这个目录 SRC_PATH确实以/.(即:斜线后跟) 结尾 源目录的内容被复制到这个目录中 其它

登录

1
2
# 登陆账号,用于上传镜像到 Docker Hub
docker login -u username
上传到 Docker Hub,需将 镜像的 repository 部分 与 Docker Hub用户名相匹配 完整镜像名: [username]/xxx:tag 补充:Docker 官方自己维护的镜像无用户名部分

Docker 安装 MySQL

参考: mysql - Docker Hub 详解使用DockerHub官方的mysql镜像生成容器 - adolfmc - 博客园

1. docker 方式

1
docker run --name demo-mysql-container -v /home/mysql_data:/var/lib/mysql -p 3307:3306 -e MYSQL_ROOT_PASSWORD=demo-root-pw -e MYSQL_DATABASE=demodb -d mysql
--name 指定容器名 demo-mysql-container -v 将宿主机 /home/mysql_data 挂载到 容器内 /var/lib/mysql 目录 挂载:可以理解为 将 /home/mysql_data 与 /var/lib/mysql 连接了起来,成为了一块共享区域,在宿主机修改 /home/mysql_data 等同 修改容器内 /var/lib/mysql ,反之亦然。 -p 将宿主机 3307 映射到 容器内 3306 端口 注意:docker容器内 mysql实例 默认监听3306端口,所以一定是映射到容器内 3306端口, 如需修改默认端口,需修改mysql容器内mysql配置文件 /etc/mysql/conf.d,一般来说这没有必要,容器彼此之间是隔离的,不存在端口占用情况,但如果宿主机 3306端口被占用,就不能映射到宿主机3306了,所以这里是 3307:3306 -e 后为环境变量(Environment Variables)
1
MYSQL_ROOT_PASSWORD=demo-root-pw
MySQL 的 root 用户密码为:demo-root-pw
1
MYSQL_DATABASE=demodb
在镜像创建为容器启动时,将创建一个名为 demodb 的数据库,当存在MySQL用户时,此用户将拥有对此数据库的 superuser 权限。 -d 在后台运行 最后的 mysql 为 使用官方 mysql 镜像,可使用 mysql:tagName 指定标签版本。 补充: 在当前目录下挂载 MySQL 数据目录,利用 $PWD变量
1
-v "$PWD/mysql_data":/var/lib/mysql
补充: 通过命令指定字符编码,而无需更改 MySQL配置文件
1
docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
1
--character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

2. docker-compose.yml 方式

docker-compose.yml
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
version: '3.1'

services:

demo-mysql-service:
container_name: demo-mysql-container
image: mysql
command: --default-authentication-plugin=mysql_native_password
ports:
- 3307:3306
restart: always
environment:
MYSQL_ROOT_PASSWORD: demo-root-pw
MYSQL_DATABASE: demodb
networks:
- demo-network

demo-web-service:
container_name: demo-web-container
build:
context: .
dockerfile: Dockerfile
ports:
- 8080:5000
restart: always
networks:
- demo-network

networks:
demo-network:
driver: bridge

查看docker镜像磁盘空间占用情况

1
docker system df

清理 <none>:<none> 镜像

1
docker image prune

清理

1
docker system prune
该指令默认会清除所有如下资源: 已停止的容器(container) 未被任何容器所使用的卷(volume) 未被任何容器所关联的网络(network) 所有悬空镜像(image)。 该指令默认只会清除悬空镜像,未被使用的镜像不会被删除。添加-a 或 --all参数后,可以一并清除所有未使用的镜像和悬空镜像。 可以添加-f 或 --force参数用以忽略相关告警确认信息

无法启动容器

1
driver failed programming external connectivity on endpoint simcaptcha-container 
1
ERROR: for simcaptcha-container  Cannot start service simcaptcha.service: driver failed programming external connectivity on endpoint simcaptcha-container (dc434a8d5611ac961ad5212403a826fe8ea3943a69227b400e6fc11d7469752f): Bind for 0.0.0.0:5004 failed: port is already allocated
解决: 重启docker
1
systemctl restart docker
参考: docker端口映射或启动容器时报错 driver failed programming external connectivity on endpoint quirky_allen_whatday的专栏-CSDN博客 Docker遇到的异常和注意点-布布扣-bubuko.com

以 root 权限

1
2
privileged: true
user: root
privileged: true 大约在0.6版,privileged 被引入 Docker。
使用该参数,container内的 root 拥有真正的 root 权限。
否则,container 内的 root 只是外部的一个普通用户权限。
privileged 启动的容器,可以看到很多 host 上的设备,并且可以执行 mount。
甚至允许你在 docker 容器中启动 docker 容器。 user: root 通过 user 指令限定了缺省用户, 进入之后直接显示的是root 用户
docker-compose.yml
1
2
3
4
5
6
7
8
9
10
11
version: '3.4'

services:
plugincore.service:
image: yiyungent/plugincore-aspnetcore3-1
container_name: plugincore-aspnetcore3-1-container
ports:
- "5007:80"
privileged: true
user: root
restart: always
补充: 对应
1
docker run --user root --privileged=true

健康检查 up (healthy)

参考:
- Docker 容器健康检查机制
- docker - What does the "(healthy)" string in STATUS stands for? - Stack Overflow
- Docker 健康检查功能_weixin_34088838的博客-CSDN博客

Volume

Volume 可以叫做 数据卷,可供一个或者多个容器使用:
- 数据卷 可以在容器之间共享和重用
- 对 数据卷 的修改会立马生效
- 对 数据卷 的更新,不会影响镜像
- 数据卷 默认会一直存在,即使容器被删除

镜像备份

这里说的备份指的是直接从本地备份镜像文件,可以使用 docker save 命令将镜像打包成 tar 文件,之后可以使用 docker load 命令来恢复。
1
2
docker save -o /path/to/image.tar image-name:1.0.0
docker load -i /path/to/image.tar

容器备份

备份容器有不同的方法: 通过 [docker commit] 命令来提交一个基于当前容器状态的新镜像 使用 [docker export] 命令来将容器导出到系统文件并压缩成 tar,之后可以根据该 tar 文件使用 docker import 来创建新的镜像 需要注意的是所有的命令都只会备份容器 layered file system ,不包括 挂载的数据卷 Volumes

数据卷操作

Docker user guide 中有非常详细的知道,如何备份数据卷,这样就可以在新容器启动时使用备份好的数据。当备份 data volume 时,需要先关闭容器。
1
2
3
4
5
6
7
8
9
10
11
docker volume create my-vol          # 创建数据卷
docker volume ls # 查看所有数据卷
docker volume inspect my-vol # 查看指定数据卷内容
docker run -d -P \
--name web \
# -v my-vol:/wepapp \
--mount source=my-vol,target=/webapp \
training/webapp \
python app.py # 启动并挂载一个数据卷 使用 `--mount`
docker inspect web # 查看容器中 mount 信息
docker volume rm my-vol # 移除数据卷
数据卷 是被设计用来持久化数据的,它的生命周期独立于容器,Docker 不会在容器被删除后自动删除 数据卷,并且也不存在垃圾回收这样的机制来处理没有任何容器引用的 数据卷。如果需要在删除容器的同时移除数据卷。可以在删除容器的时候使用 docker rm -v 这个命令。 无主 (dangling) 的数据卷可能会占据很多空间,要清理请使用以下命令
1
docker volume prune

数据卷备份

比如在 docker compose 中定义了叫做 db_data 的 volume:
1
2
volumes:
db_data:
那么在启动 docker compose 之后会生成一个 DOCKER_COMPOSE_NAME 加上 VOLUME_NAME 的容器卷
1
[DOCKER_COMPOSE_NAME]_[VOLUME_NAME]
那么可以使用下面的命令来备份该数据卷:
1
2
3
4
5
docker run --rm \
--volume [DOCKER_COMPOSE_PREFIX]_[VOLUME_NAME]:/[TEMPORARY_DIRECTORY_TO_STORE_VOLUME_DATA] \
--volume $(pwd):/[TEMPORARY_DIRECTORY_TO_STORE_BACKUP_FILE] \
alpine \
tar cvf /[TEMPORARY_DIRECTORY_TO_STORE_BACKUP_FILE]/[BACKUP_FILENAME].tar /[TEMPORARY_DIRECTORY_TO_STORE_VOLUME_DATA]
看清楚其中的临时 DATA 目录和 临时备份目录,执行该命令之后,在当前文件夹下就会产生 BACKUP_FILENAME.tar 这样的文件,里面包含数据卷中的内容。 这一行语句包含两个 volume,举例使用说明,假如有一个数据卷叫做 chevereto_chevereto_data,要备份该数据卷:
1
2
3
4
5
docker run --rm \
--volume chevereto_chevereto_data:/tmp \
--volume $(pwd):/path_to_store_backup \
alpine \
tar cvf /path_to_store_backup/chevereto_chevereto_data.tar /tmp
那么就能够使用该命令来恢复数据卷数据:
1
2
3
4
5
docker run --rm \
--volume [DOCKER_COMPOSE_PREFIX]_[VOLUME_NAME]:/[TEMPORARY_DIRECTORY_STORING_EXTRACTED_BACKUP] \
--volume $(pwd):/[TEMPORARY_DIRECTORY_TO_STORE_BACKUP_FILE] \
alpine \
tar xvf /[TEMPORARY_DIRECTORY_TO_STORE_BACKUP_FILE]/[BACKUP_FILENAME].tar -C /[TEMPORARY_DIRECTORY_STORING_EXTRACTED_BACKUP] --strip 1
恢复数据卷数据,举例:
1
2
3
4
5
docker run --rm \
--volume chevereto_chevereto_data:/tmp \
--volume $(pwd):/path_to_store_backup \
alpine \
tar xvf /path_to_store_backup/chevereto_chevereto_data.tar -C /tmp --strip 1
如果是数据库容器,比如 MySQL 容器,备份数据可以使用如下方式
1
docker exec [CONTAINER_NAME] /usr/bin/mysqldump -u root --password=root [DATABASE] > backup.sql
然后使用下面的命令来恢复
1
cat backup.sql | docker exec -i [CONTAINER_NAME] /usr/bin/mysql -u root --password=root [DATABASE]
对于 docker compose 启动的多个容器,可能因为宿主机器变化而导致 docker 容器的 id 有变化,可能在回复数据之后,还需要对数据库连接的地址进行修改才能完整的恢复。

常用

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
docker version   # 查看版本信息

docker info # 显示统信息,包括镜像和容器数

docker images # 查看镜像 (docker images -a 含中间镜像层)

docker rmi 镜像ID # 删除单个镜像

docker rmi -f 镜像ID # 强制 删除单个镜像

docker rm 容器ID # 删除单个容器

docker run -it REPOSITORY bash 启动镜像
--name="容器新名字": 为容器指定一个名称;
-d: 后台运行容器,并返回容器ID,也即启动守护式容器;
-i:以交互模式运行容器,通常与 -t 同时使用;
-t:为容器重新分配一个伪输入终端,通常与 -i 同时使用;
-P: 随机端口映射;
-p: 指定端口映射;

# 进入容器, 并新开 Terminal 执行 bash
docker exec -it 容器ID bash

docker ps # 查看正在运行容器

docker ps -a # 查看所有容器

docker start 容器ID或者容器名 # 启动容器

docker restart 容器ID或者容器名 # 重启容器

docker stop 容器ID或者容器名 # 停止容器

docker kill 容器ID或者容器名 # 强制停止容器

docker kill $(docker ps -a -q) # 停用全部运行中的容器

docker rm $(docker ps -aq) # 删除全部容器

docker rmi `docker images -q` # 删除所有镜像

查看 Docker 容器占用内存

参考: 查看docker容器占用内存 - sucre_tan - 博客园 Linux top 命令 | 菜鸟教程
1
2
3
ps -ef|grep 容器ID

top -p 7358(pid)
参数说明:
- PID:进程的ID
- USER:进程所有者
- PR:进程的优先级别,越小越优先被执行
- NInice:值
- VIRT:进程占用的虚拟内存
- RES:进程占用的物理内存
- SHR:进程使用的共享内存
- S:进程的状态。S表示休眠,R表示正在运行,Z表示僵死状态,N表示该进程优先值为负数
- %CPU:进程占用CPU的使用率
- %MEM:进程使用的物理内存和总内存的百分比
- TIME+:该进程启动后占用的总的CPU时间,即占用CPU使用时间的累加值。
- COMMAND:进程启动命令名称 top 命令经常用来监控 linux 的系统状况,是常用的性能分析工具,能够实时显示系统中各个进程的资源占用情况。

/bin/bash: /bin/bash: cannot execute binary file

Dockerfile
1
2
3
# ...

ENTRYPOINT ["/bin/bash"]
这样做后,会导致
1
docker run -it --name bayes-svm-knn-container bayes-svm-knn /bin/bash
报错:
1
/bin/bash: /bin/bash: cannot execute binary file

阻止 Docker 容器 自动退出

1
2
3
cd /root/bayes-svm-knn

docker run -d -it --name bayes-svm-knn-container -v {{hbeSeoContent}}#123;PWD}/code:/app/code -v {{hbeSeoContent}}#123;PWD}/data:/app/data bayes-svm-knn bash
注意
一定要加上 -d -it bash, 这样容器才不会自动退出,
如果 docker attach bayes-svm-knn-container 进入主进程 bash 后,再 Ctrl+D 则会导致主线程退出,容器结束, 可以使用 Ctrl+P+Q 退出而不终止容器运行,
docker exec -it bash 的方式是新开 Session 终端, 因此 Ctrl+D 不会终止容器运行 PS:
docker -v 中 host 不能使用 相对路径, 必须使用 绝对路径, 但在 docker-compose.yml 就可以使用相对路径
1
docker exec -it bayes-svm-knn-container bash

CMD 与 ENTRYPOINT

参考: Dockerfile reference | Docker Documentation Docker-Compose Entrypoint/Command - Stack Overflow docker容器之dockerfile&docker-compose CMD/entrypoint详解 - Marathon-Davis - 博客园 Docker Compose 配置文件 Docker-Compose.yml 文件详解_liguangxian2018的博客-CSDN博客_docker-compose.yml - docker-compose.yml 配置文件 常用详解

/bin/bash -c

参考: /bin/bash -c 的意思 - 简书 linux - What is /bin/sh -c? - Stack Overflow -c 命令表示后面的参数将会作为字符串读入 作为执行的命令 举个例子,尝试在本地执行下面两个命令: /bin/bash -c ls /bin/bash ls 可以看到, /bin/bash -c 后面接 命令 ,而 /bin/bash 后面接 执行的脚本。 注意: 如果后面的命令有空格, 则用引号括起来, 例如
1
/bin/bash -c "ls /root"

docker 容器 命名规则

对于一个合法的容器的名称来说只可以包括以下字符:小写字母a~z 、大写字母A-Z 、数字0~9 、下划线 、圆点 、横线

docker-compose.yml 中 build.context

1
2
3
4
5
- me/
- code/
- Dockerfile
- docker-compose.yml
- requirements.txt
1
2
3
cd me/code

docker-compose up -d
docker-compose.yml
docker-compose.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
version: '3.1'

services:

# 朴素贝叶斯
train_bayes_bnb_model_bag:
build:
context: ../
dockerfile: ./code/Dockerfile
container_name: train_bayes_bnb_model_bag-container
image: train_bayes_bnb_model_bag
entrypoint: /bin/bash -c "cd /app/code/train_scripts && python train_bayes_bnb_model_bag.py"
volumes:
- ../code:/app/code
- ../data:/app/data
此时, build.context 即 通过 ../ 跳出此层, 于是在 me/ 注意: build.dockerfile 路径相对于 build.context 所指定的路径 注意: Dockerfile 中的源路径 也是 相对于 build.context 的路径
> Dockerfile
Dockerfile
1
2
3
4
WORKDIR /app

RUN mkdir code data
COPY ["./code/requirements.txt", "./code"]
注意: docker-compose.yml 中 volumes 宿主机路径 是相对于 执行 docker-compose up 处的路径, 而不是 build.context 路径 PS:
- 想避免一些路径问题, 可以指定 docker-compose.yml 路径,如下方:
1
docker-compose -f ./code/docker-compose.yml up -d

docker-compose.yml 限制内存, CPU

参考: docker-compose限制内存, cpu资源以及固定ip写法 - 培天王 - 博客园 在docker内设置内存与CPU限制 - 小不的笔记

docker-compose 对单个服务的操作

参考: docker-compose - docker-compose-重新启动单个服务的问题 - Thinbug

启动 docker-compose.yml 内单个服务

1
docker-compose up -d train_bayes_bnb_model_bag

多架构 构建

参考: Docker buildx构建多平台镜像并推送到私有仓库的方法_docker_脚本之家 docker buildx build | Docker Documentation build-push-action/multi-platform.md at master · docker/build-push-action buildx/README.md at master · docker/buildx build-push-action/push-multi-registries.md at master · docker/build-push-action docker/setup-buildx-action: GitHub Action to set up Docker Buildx docker/build-push-action: GitHub Action to build and push Docker images with Buildx 使用 docker buildx 实现多平台编译 - 案例篇 - 知乎 使用GitHub Action构建全平台docker镜像 | sleele的博客 Multi-arch build and images, the simple way - Docker - Docker 官方博文 - 推荐 Docker是一个虚拟化平台,而不是仿真器。
它不能用于在另一个架构上运行来自一个架构的映像(在ARM上运行AMD64,反之亦然)。你需要一个匹配的映像。 GitHub Action 片段
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- name: Login to Registry - ghcr.io
run: echo "{{hbeSeoContent}}#123;{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u {{hbeSeoContent}}#123;{ github.actor }} --password-stdin

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1

- name: Build Image And Push - ghcr.io
run: |
IMAGE_ID=ghcr.io/{{hbeSeoContent}}#123;{ github.repository_owner }}/{{hbeSeoContent}}#123;{ steps.vars.outputs.IMAGE_NAME }}
VERSION={{hbeSeoContent}}#123;{ steps.vars.outputs.RELEASE_VERSION }}
echo IMAGE_ID=$IMAGE_ID
echo VERSION=$VERSION
docker buildx build \
--platform=linux/amd64,linux/arm64 \
--output "type=image,push=true" \
--file Dockerfile \
--tag $IMAGE_ID:$VERSION \
1
2
3
# buildx 可以指定多个平台,但是要求 Dockerfile 中的 FROM 镜像必须有对应版本的。
# buildx 打包的镜像不会在本地存储,加--push,上传docker仓。或者可以使用--output指定输出方式。
docker buildx build --platform linux/amd64,linux/arm64 -t buildx.com/base/java-base:openjdk-8-centos7 . --push
参考 感谢帮助! Docker - Image镜像创建及容器操作 《每天5分钟玩转Docker容器技术》CloudMan Dockerfile文件详解 - 百衲本 - 博客园 增加自动构建到 docker hub 的 github actions by yezige · Pull Request #182 · v2fly/v2ray-core Visual Studio Container Tools build and debug overview - Visual Studio | Microsoft Docs Watchtower - 自动更新 Docker 镜像与容器 - P3TERX ZONE 监控 docker 运行数据 stats 命令 | Verne in GitHub 备份 Docker 镜像容器和数据以及无痛迁移 | Verne in GitHub