写点什么

精彩推荐 | 【深入浅出 Docker 原理及实战】「原理实战体系」零基础 + 全方位带你学习探索 Docker 容器开发实战指南(实战技术总结)

作者:洛神灬殇
  • 2024-01-25
    江苏
  • 本文字数:4590 字

    阅读完需:约 15 分钟

精彩推荐 | 【深入浅出Docker原理及实战】「原理实战体系」零基础+全方位带你学习探索Docker容器开发实战指南(实战技术总结)

前提介绍

在使用 Docker 时,管理维护工作可能会显得复杂。然而,实际上,Docker 提供了许多便捷且人性化的工具,这些工具的使用技巧可以大大简化维护工作,并提升效率。通过掌握这些技巧,你不仅能够更轻松地管理 Docker 环境,还能展现出专业的能力。接下来我们就给大家介绍一下对于我在工作当中对于 Docker 容器使用的技术实战总结

实战总结方案

创建容器时传入环境变量

在现实应用中,出于安全和配置灵活性的考虑,许多参数适宜通过环境变量进行设置,例如数据库连接信息、时区设置以及字体支持等。在创建容器时,您可以使用 -e 参数为这些环境变量指定键值对,从而实现参数的传递和配置。这样的方式不仅方便灵活,还有助于提高应用的安全性。


root# docker run -itd --name add-env -e TZ='Asia/Shanghai' centos7.2-jdjr-add-app de20b44301e27c16eae63dab243d293054178dd5f819c23d44bd9e534208bb42
复制代码


在 Docker 命令中,你可以使用环境变量来配置应用的行为。你给出的命令是一个 Docker 运行的示例,其中使用了-e参数来设置环境变量TZ的值为Asia/Shanghai,这表示将时区设置为上海。


root# docker exec -it test-env date2024年 01月 17日 星期三 10:35:17 CSTroot# dateTue Jan 17 10:35:21 CST 2024
复制代码


可以看到加了时区环境变量的容器已经和宿主机在同一个时区(CST),并且时间和宿主机基本同步,我们再来看一下不加入时区设置的。


root# docker run -itd --name add-env centos7.2-jdjr-add-appd6a02874b999fd5eea79e3b302148b42043af01c89a5d31e5d858e0806f9077aroot# docker exec -it add-env date
复制代码


大家可以看到容器的时间是:2024 年 01 月 20 日 星期六 01:43:48 Asia,没有加时区环境变量的容器还是 Asia。

调整宿主机和容器的时间差异

对于 Docker 容器来说,宿主和容器之间的时间差异并不存在,因为它们共享同一个内核和时钟。这意味着它们的时间是同步的,不存在需要特别处理的时间同步问题。通常,时间问题更多是由时区差异引起。你可以使用date命令来查看容器当前的时区设置。


通用协调时(UTC)是国际标准 0 时区,与格林尼治平均时(GMT)相同,即英国伦敦的本地时间。而 CST 通常表示中国标准时间,与 UTC 相差 8 小时。


在类 Unix 系统中,存在硬件时钟系统时钟两个概念。



Unix 和 Linux 系统的时钟时间是从格林威治时间(GMT)开始计算的当前秒数,即从 1970 年 1 月 1 日凌晨零点零分零秒至今的时间。这是一个全球统一的标准,不受地理位置差异的影响。


时区是为了克服时间上的混乱,根据地理位置和行政区域划分的。全球共划分为 24 个时区,我国属于东八区,并采用协调世界时(UTC)作为标准时间。

解决办法

创建容器的时候,使用-e 将时区信息传入到容器内部。


其实使用单纯的环境变量来改变容器内部的 TIME ZONE,只会影响当前容器用户的时区,一旦切换到真正的 root 用户就会发现时区依然是不正确的,比如以下栗子:


root#root# docker run -itd --name test-env -e TZ='Asia/Shanghai' imagesroot# docker exec -it test-env bashroot# date2024年 01月 17日 星期三 20:45:54 CSTroot# sudo su -c date2024年 01月 18日 星期三 08:46:02 EDTroot# 
复制代码


那么如何真正解决时区这个问题呢?其实是/etc/localtime 在作怪,用户只需要将容器内部的 localtime 改成你想要的时区就行了。


root# ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime root# date2024年 01月 17日 星期三 20:49:54 CSTroot# sudo su -c date2024年 01月 17日 星期三 20:49:54 CSTroot# 
复制代码


在使用 Dockerfile 构建镜像的时候将/usr/share/zoneinfo/Asia/Shanghai 强制软连接到/etc/localtime 就可以永久修复时区的问题了。


RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime;\    rm /bin/sh && ln -s /bin/bash /bin/sh;\    echo 'Asia/Shanghai' >/etc/timezone
复制代码

指定容器的 rootfs 的大小

在使用 Docker 时,CPU 和内存可以灵活地动态调整,但默认的 rootfs 大小却是固定的,默认为 10GB。对于需要扩展存储的用户,可以通过挂载 volume 来实现。


对于需要调整 rootfs 大小的用户,Docke 提供了两种方式:在启动 Docker 时加载参数--storage-opt dm.basesize=40G来调整默认容器的 rootfs 大小;在创建容器时使用参数--storage-opt size=70G来设置特定容器的 rootfs 大小。这些调整方法使得用户可以根据实际需求来定制和优化容器存储空间。


docker run -itd --name add-test --storage-opt size=70G centos7.2-jdjr-add-app
复制代码


接下来,我们看到容器被成功创建并开始运行:


18d47e69802aa84df00182885b256c50ebc56e15d8e6990fc1e187ffe254171e


然后,我们使用以下命令来检查容器的磁盘使用情况:


docker exec -it add-test df -H | grep rootfs


进入到名为add-test的容器,并执行df -H命令来查看磁盘使用情况,然后通过grep rootfs来筛选出与 rootfs 相关的结果。结果显示 rootfs 的大小为 76G,已使用 1.5G,还剩 74G,使用率为 2%。


root# docker run -itd --name add-test --storage-opt size=70G centos7.2-jdjr-add-app18d47e69802aa84df00182885b256c50ebc56e15d8e6990fc1e187ffe254171eroot# docker exec -it add-test df -H | grep rootfsrootfs                 76G  1.5G   74G   2% /root# docker exec -it add-env df -H | grep rootfsrootfs                 11G  1.5G  9.3G  14% /
复制代码

快速管理容器和镜像

在 Docker 中,删除容器需要指定容器名或容器 ID。当容器数量众多且状态各异时,删除容器需要更加谨慎。然而,Docker 的docker ps命令提供了许多实用的功能,方便用户管理容器。在创建容器时,通过添加标签(label)可以进一步简化容器的管理。

快速删除容器的原理

Docker 的原理是使用 container id 来唯一标识一个容器,因此可以通过获取所有容器的 container id 来批量删除它们。使用docker ps -a -q命令可以输出所有容器的 container id,其中-a参数表示输出所有容器,-q参数表示只输出 container id。然后,将这些 id 作为参数传递给docker rm命令进行批量删除。这样可以快速地清理不再需要的容器,提高管理效率。

--format 格式化输出

在 Docker 的底层实现中,各种容器的组织信息确实存储在结构体中,其中*formatter.containerContext可能是与容器格式化输出相关的结构体之一。这个结构体可能包含了用于生成容器输出所需的字段和数据。


通过使用--format选项,用户可以定义自己的模板,并利用 Go 模板语法来格式化容器的输出。这使得用户可以根据自己的需求定制化输出,更加灵活地展示容器信息。

输出所有容器的 name

root# docker ps --format='{{.Names}}'test-envtest-apptest-run
复制代码

输出所有容器名包含 test 的容器

root# docker ps -f name=test --format='{{.Names}}'test-envtest-apptest-run
复制代码

查看退出状态的容器

root# docker ps -f status=exited --format="{{.Names}}"thirsty_brahmaguptaclever_mestorfhopeful_morsestoic_morseelated_williamstender_jepsenreverent_mirzakhani
复制代码

删除所有容器

root# docker rm -f -v $(docker ps -a -q)
复制代码

删除/启动所有退出的容器

root# docker rm $(docker ps -qf status=exited) 
复制代码


会删除所有已退出的容器。


docker start $(docker ps -qf status=exited) 
复制代码


会启动所有已退出的容器。

快速删除容器的原理

只列出镜像的 id 以及仓库名称:


sh-4.2# docker images --format "{{.ID}}: {{.Repository}}"


67591570dd29: centos0a18f1c0ead2: rancher/server


只列出容器的相关 id,image,status 和 name


sh-4.2# docker ps --format "{{.ID}}: {{.Image}} : {{.Status}} : {{.Names}}"66b60b72f00e: centos : Up 7 days : pensive_poincare 或者自己重新定义列,就和原生差不多:


sh-4.2# docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Status}}\t{{.Names}}"CONTAINER ID IMAGE STATUS NAMES66b60b72f00e centos Up 7 days pensive_poincare

删除所有镜像

root# docker rmi $(docker images -q)
复制代码

容器的自动重启机制

您可以使用--restart参数来配置 Docker 容器的重启策略。其中,--restart=always选项表示容器将始终自动重启,无论容器是否正常退出。


要使容器随着 Docker 守护进程的启动而一同启动,您可以在运行容器时加上--restart=always参数,例如:


docker run --restart=always <image_name>
复制代码


这将使容器在 Docker 守护进程启动时自动创建并启动。即使容器正常退出或发生错误,它也会自动重新启动。


注意,使用--restart=always可能会对系统资源造成一定的负担,因为容器会不断地重新启动。如果不需要容器始终自动重启,您可以考虑使用其他重启策略,如--restart=on-failure--restart=unless-stopped,以仅在容器退出状态不为 0 或您手动停止容器时重启。

如何动态修改容器的内存和 cpu 限制

root# docker exec add-env cat /sys/fs/cgroup/memory/memory.limit_in_bytes9223372036854775807root# cat /sys/fs/cgroup/memory/memory.limit_in_bytes 9223372036854775807
复制代码


可以看到,默认没有给容器限制内存,它会共享宿主机的所有内存动态调整内存为 2014M:


root# docker update -m 2014M add-envadd-envroot# docker exec test-env cat /sys/fs/cgroup/memory/memory.limit_in_bytes2111832064
复制代码

使用 alias 来预定义常用的命令

docker 管理命令经常需要指定各种参数,通过 linux 的 alias 命令将默认的参数预定义起来,可以很方便的进行管理容器。


root# alias dockerrm='docker rm -f -v'root# alias dockerexec='docker exec -it'root# alias dockerrmimage='docker rmi'
root# dockerrm volume-testvolume-test
root# dockerexec volume-test lsbin dev export lib media opt root selinux sys usrboot etc home lib64 mnt proc sbin srv tmp var
复制代码

容器 label 的使用

在运维工作中,随着容器的增多,管理和维护的复杂性也相应增加。然而,借助 label 这一功能,可以轻松地对容器进行分类和标识。


label 不仅仅用于简单的标识,它还贯穿于 Docker 的整个生命周期,从创建到管理,再到运行。通过为容器设置不同的 label,可以清晰地划分出不同业务、不同模板的容器,从而更方便地进行分组和运维。因此,合理使用 label 功能,可以大大提高容器管理的效率和便捷性。


root# docker run -itd --name volume-test --storage-opt size=70G --label zone=test centos7.2-jdjr-test-appc3772397e58e663095c2c0fd8d688b3d41b494097999ec2b6d6b7c509d23a138
复制代码


创建容器的时候定义一个 label,表示该容器在 test 这个区域使用定义的 label 进行快速检索容器,并进行下一步操作。


root# docker ps -qf label=zone=testc3772397e58eroot# docker ps -f label=zone=test --format='{{.Names}}'volume-test
复制代码

快速查看容器的相关配置信息

查看容器的 devicemapper 设备

root# docker inspect -f '{{.GraphDriver.Data.DeviceName}}' nginx docker-18:1-67411759-7c9d6d3327b02659c81bcb70bf6a4c7a45df6a589af2a2d42a387dc0e90d4913
复制代码

查看容器的 PID

root# docker inspect -f '{{.State.Pid}}' nginx 27521
复制代码

查看容器 name

root# docker inspect -f '{{.Name}}' nginx /nginx
复制代码

获取容器的 ID:

root# docker inspect --format {{.Id}} nginx53214bc9cd001f2c548edcce0c42fe51f1a118c08941406d43122a8348055843
复制代码


发布于: 刚刚阅读数: 4
用户头像

洛神灬殇

关注

🏆 InfoQ写作平台-签约作者 🏆 2020-03-25 加入

👑 后端技术架构师,前优酷资深工程师 📕 个人著作《深入浅出Java虚拟机—JVM原理与实战》 💻 10年开发经验,参与过多个大型互联网项目,定期分享技术干货和项目经验

评论

发布
暂无评论
精彩推荐 | 【深入浅出Docker原理及实战】「原理实战体系」零基础+全方位带你学习探索Docker容器开发实战指南(实战技术总结)_Docker_洛神灬殇_InfoQ写作社区