Docker 常用技巧

1 修改已创建的容器的配置

此方法有点粗暴,生产环境慎用 参考自CSDN-linux 已经创建的容器container 如何挂载共享文件夹 如何更改端口

  • 使用 docker -ps -a 拿到需要更改的container的ID
  • 停止所有container 并使用service docker stop(ubuntu平台)关闭docker服务
  • 到目录 /var/lib/docker/containers/<容器ID>/中修改 config.v2.jsonhostconfig.json,注意文件的提前备份
  • 重启docker服务service docker start

1.1 修改或增加端口信息

  • 在文件hostconfig.json中修改或增加PortBindings的内容,以将容器端口22映射到服务器端口10022为例:"22/tcp":[{"HostIp":"","HostPort":"10022"}]
  • 在文件config.v2.json中修改或增加ExposedPorts的内容,以将容器端口22映射到服务器端口10022为例:"22/tcp":{}

相关实践:配置远程开发环境

1.2 修改或新增共享文件夹

  • 在文件hostconfig.json中修改或增加Binds的内容,格式是 "主机目录:容器目录",以将容器文件夹/data/share与服务器文件夹/data/share共享为例:["/data/share:/data/share"]
  • 在文件config.v2.json中修改或增加MountPoints的内容,以将容器文件夹/data/share与服务器文件夹/data/share共享为例,具体格式如下:
"MountPoints":{"/data/share":{"Source":"/data/share","Destination":"/data/share","RW":true,"Name":"","Driver":"","Type":"bind","Propagation":"rprivate","Spec":{"Type":"bind","Source":"/data/share","Target":"/data/c"}}}

相关实践:Syncthing文件夹同步

2 运行中容器修改端口映射

# 1. 查看容器的IP信息
docker inspect `container_name` | grep IPAddress
# 2. 查看NAT表中的PREROUTING链(确保其中包含DOCKER链)
iptables -t nat --list-rules PREROUTING
# 无DOCKER链时,根据下行代码手动添加
# iptables -t nat -A PREROUTING -p tcp -m addrtype --dst-type LOCAL -j DOCKER
# 3. 查看NAT表中的DOCKER链
iptables -t nat --list-rules DOCKER
# 4. 仿照已有的DOCKER链添加映射规则(以容器内8812映射到主机8112为例)
iptables -t nat -A DOCKER ! -i docker0 -p tcp -m tcp --dport 8112 -j DNAT --to-destination 10.8.0.6:8812
# 重复步骤3可查看是否添加成功
# 5. 查看NAT表中的POSTROUTING链
iptables -t nat --list-rules POSTROUTING
# 6. 仿照已有的POSTROUTIN链添加规则
iptables -t nat -A POSTROUTING -s 10.8.0.6/32 -d 10.8.0.6/32 -p tcp -m tcp --dport 8812 -j MASQUERADE
# 重复步骤5可查看是否添加成功
# 7. 查看FILTER表中的DOCKER链
iptables --list-rules DOCKER
# 8. 仿照FILTER表中的DOCKER链添加规则
iptables -t filter -A DOCKER -d 10.8.0.6/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 8812 -j ACCEPT
# 9.添加规则命令中的-A换成-D即可删除规则

参考:docker容器启动后增加端口映射办法

3 使用docker cp命令挽救无法启动的容器

  • 使用docker cp命令,把docker容器中的出错文件复制到主机中来
  • 将修改后的文件再复制到docker容器中,然后启动容器

docker cp 容器外地址 容器ID:容器内地址

4 docker ps 过滤

docker ps -f 'name='reg_string_' 仅过滤查找启动中的容器

docker ps -a -f 'name='reg_string_' 过滤查找所有的容器

5 创建镜像方法对比

主要包括docker save/load、docker export/import及docer commit

  • docker save/load基于已有镜像创建镜像,结果带有历史信息(可回溯),常用于镜像的分享
  • docker export/import基于容器创建镜像,结果不带历史信息(不可回溯),多用于镜像迁移
  • docer commit基于容器创建镜像,结果带有历史信息(可回溯),会保留容器相比于原镜像新增的内容,可用于镜像的调整与升级

具体参考:docker save和docker export及docer commit命令的区别

6 docker stats 查看资源使用

默认是实时动态统计,可添加参数--no-stream (只返回当前的状态)输出静态统计

统计结果主要包括:PID、CPU、内存、网络IO、磁盘IO信息

docker system df [-v] 可以查看 Docker 服务的整体空间占用

7 容器与环境变量设置

正常情况下通过参数-e--env可以在docker run的时候手动设定环境变量

docker run --env test_var='THANKS' -dit --name=test -p 10222:22  images_name /bin/bash

其次当需要批量导入环境变量时,docker run可使用参数--env-file

环境变量导入成功后,可通过以下命令查看容器的环境变量

docker exec container_id env
docker inspect container_id # 另一种查看方法

远程工作环境中,常出现容器搭配sshd的方式,而通过ssh建立连接的过程中,环境变量会被重置,导致用户无法获取容器启动时配置的环境变量

解决方案:由于ssh连接后,会自动执行source /etc/profile,因此可以在文件 /etc/profile后追加下面这句代码:

# 从1号进程获取容器本身的环境变量,然后导入这些环境变量
export $(cat /proc/1/environ |tr '\0' '\n' | xargs)

补充知识:容器配置的环境变量不会存在于容器中的环境变量文件中,而是作为进程的环境变量,存在于对应进程的内存,举例(查看进程9527的环境变量):

cat /proc/9527/environ | tr '\0' '\n'

参考:解析docker中的环境变量使用和常见问题解决

8 容器外查找容器的文件系统

查看容器的基本信息:

docker inspect container_id

其中包括以下部分内容:

{
  "Data": {
    "LowerDir": "/var/lib/docker/overlay2/container_parent_id2-init/diff:/var/lib/docker/overlay2/container_parent_id2/diff",
    "MergedDir": "/var/lib/docker/overlay2/container_id/merged",
    "UpperDir": "/var/lib/docker/overlay2/container_id/diff",
    "WorkDir": "/var/lib/docker/overlay2/container_id/work"
  },
  "Name": "overlay2"
}
  • LowerDir:只读的镜像层
  • UpperDir:容器的读写层,保留文件的修改操作
  • WorkDir:中间层,临时保存修改,最终传递至读写层
  • MergedDir:整合只读层和读写层的最终合并统一视图
  • MergedDir对应容器的文件系统路径,适合直接在容器外修改文件

除此之外,也可以在inspect结果中找到容器对应的主机PID,然后通过命令ls /proc/<pid>/root可以直接查看进程的挂载命名空间了~

参考:Where are my container's files? Inspecting container filesystems

9 自动生成容器名称

在创建docker容器时,未使用--name参数的情况下,docker会自动生成一个名称

  • 名称生成器位于docker开发目录的pkg/namesgenerator/文件夹下
  • 名称使用两个列表进行随机组合,并在名称冲突时添加随机数作为后缀
  • 名称组合的左列表为常见形容词,右列表为著名科学家和黑客的名字

小彩蛋:docker的名称生成器会屏蔽掉boring_wozniak这一随机名称

参考:How docker generates container's names

10 快速分析优化容器镜像 Dive

Dive是用来探索和分析 docker 镜像内容的开源命令行工具

  • 可以清晰地展示镜像中的每一层文件变更
  • 展示镜像里的新增修改和删除的文件,并给出镜像优化建议
  • 快速定位镜像中的体积来源,并且分析裁剪方式
  • 适合集成在CI/CD流程中,持续观察并校验镜像体积是否发生了预期之外的增长

项目地址

个人实践

11 镜像自动化瘦身和优化 slim

Slim 将通过使用各种分析技术了解您的应用程序及其需求来优化和保护您的容器。它会丢弃您不需要的东西,从而减少容器的攻击面

常用指令

  • xray - 对目标容器镜像执行静态分析(支持对 Dockerfile 的“逆向工程”)
  • lint - 分析 Dockerfile 中的容器指令(Docker 镜像支持是 WIP)
  • build - 分析、分析和优化容器映像,生成受支持的安全配置文件
  • profile - 执行基本的容器镜像分析和动态容器分析,但不会生成优化的镜像

项目地址

12 还原容器的启动参数

给定容器名称或ID,打印运行该容器(docker run)所需的命令

docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
    assaflavie/runlike YOUR-CONTAINER

项目地址

13 docker 数据迁移

准备工作:

# 查询 Docker 默认安装路径
docker info | grep "Docker Root Dir"
# 停止服务
systemctl stop docker 
# 复制原 Docker 安装(存储)目录到新的路径
cp -a /var/lib/docker /data/ #或 rsync -avzP /var/lib/docker /data/
# 备份原目录(不要直接删除)
mv -u /var/lib/docker /var/lib/docker-old

迁移方法 1:使用软链接

# 创建软链接
ln -s /opt/docker /var/lib/docker

迁移方法 2:修改 Docker 配置

vim /etc/docker/daemon.json
#{
#	"data-root": "/opt/docker",
#}

收尾工作:

# 启动docker服务
systemctl start docker
# 确认docker信息
docker info
# 确认后删除备份目录
rm -rf  /var/lib/docker-old

参考: 【安装部署】DataEase 迁移默认 Docker 安装(存储)目录

往年同期文章