打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
牛的Docker使用技巧 转

那些让你看起来很牛逼的Docker使用技巧

在使用docker过程中,我们经常发现管理维护是一个很复杂过程,因为我们在使用docker commands的过程中,我们只会去使用我们认为简单并且熟悉的命令,然而docker本身其实是提供给我们很多便捷且人性化的工具的,如果掌握这些使用技巧,也许你的维护管理工作将会事半功倍,并且给人看起来会很牛逼的样子。

创建容器时传入环境变量

在实际应用场景中,不论是从安全还是可配置方面去考虑,很多参数是比较适合用环境变量加载进去的,比如数据库的连接信息,时区,还有字体支持等等,在创建容器的时候其实都可以使用-e 指定key/value进行传递环境变量进去。

sh-4.2# docker run -itd --name test-env -e TZ='Asia/Shanghai' 172.25.46.9:5001/centos6.8-jdjr-test-app ee20b44301e27c16eae63dab243d293054178dd5f819c23d44bd9e534208bb42sh-4.2# docker exec -it test-env date2017年 01月 17日 星期二 10:35:17 CSTsh-4.2# dateTue Jan 17 10:35:21 CST 2017可以看到加了时区环境变量的容器已经和宿主机在同一个时区(CST),并且时间和宿主机基本同步sh-4.2# docker run -itd --name test  172.25.46.9:5001/centos6.8-jdjr-test-appd6a02874b999ff4eea79e3b302148b42043af01c89a5d31e5d858e0806f9077ash-4.2# docker exec -it test date2017年 01月 20日 星期五 01:43:48 Asia默认没有加时区环境变量的容器还是Asia

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

首先我们需要弄清几个概念:在类unix系统中有硬件时钟与系统时钟,硬件时钟是指主机板上的时钟设备,也就是通常可在BIOS画面设定的时钟,系统时钟则是指kernel中的时钟。unix以及linux系统时间是从格林威治时间到当前的秒数,即1970年1月1日凌晨零点零分零秒到当前的时间,全球都一样,这是绝对值;而时区则是由于地理位置差异、行政区划导致各地显示时间的差异,为了克服时间上的混乱,规定将全球划分为24个时区,我们国家属于东八区标识为CST。

因此,对于 Docker 容器而言,根本不存在宿主和容器的时间差异问题,因为他们使用的是同一个内核、同一个时钟,二者完全一样,所以根本不存在同步问题。一般来说这个问题是由时区导致的,可以使用date命令查看下容器当前的时间时区是啥。UTC(通用协调时)表示使用的是国际标准0时区,UTC与格林尼治平均时(GMT, Greenwich Mean Time)一样,都与英国伦敦的本地时相同。CST表示中国标准时间时区一般是中国上海"Aisa/Shanghai",也就是说UTC和CST相差了8个小时。

解决办法:创建容器的时候,使用-e 将时区信息传入到容器内部。sh-4.2# docker run -itd --name test-env -e TZ='Asia/Shanghai' images

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

$ docker run -itd --name test-env -e TZ='Asia/Shanghai' images$ docker exec -it test-env bashbash-4.1# date2017年 09月 20日 星期三 20:45:54 CSTbash-4.1# sudo su -c date2017年 09月 20日 星期三 08:46:02 EDTbash-4.1# 

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

bash-4.1# ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime bash-4.1# date2017年 09月 20日 星期三 20:54:35 CSTbash-4.1# sudo su -c date2017年 09月 20日 星期三 20:54:39 CSTbash-4.1# 

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

指定容器的rootfs的大小

在使用docker的过程中,会发现cpu和memory可以很随意的动态调整,但是默认的rootfs却是不能随意调整的,默认是10g大小,当然如果对于数据有需求,可以通过挂载voulme进行扩展存储。如果用户执意想要调整rootfs的大小,在docker1.12版本默认提供了两种方式:在启动docker 的时候加载参数--storage-opt dm.basesize=40G用来调整默认容器的rootfs大小;在创建容器的时候使用参数--storage-opt size=70G来设置改容器的rootfs大小。

喜讯:在docker最近发布的1.13版本中,支持了磁盘的配额,不过还未测试

sh-4.2# docker run -itd --name volume-test --storage-opt size=70G 172.25.46.9:5001/centos6.8-jdjr-test-app18d47e69802aa84df00182885b256c50ebc56e15d8e6990fc1e187ffe254171esh-4.2# docker exec -it volume-test df -H | grep rootfsrootfs                 76G  1.5G   74G   2% /sh-4.2# docker exec -it test-env df -H | grep rootfsrootfs                 11G  1.5G  9.3G  14% /

快速管理容器和镜像

在docker中删除容器需要指定容器名或者容器id,但是在容器比较多,并且状态不一的情况下删除容器还是需要走下心的。不过好处是docker ps默认提供了很多好用的功能,可以很方便地管理容器(创建容器的时候如果加上label后更方便哦)。

原理:先用docker ps -a -q 输出所有容器的container id(-f 表示过滤参数或者输出格式),然后作为docker rm 的参数进行批量删除输出所有容器的name:sh-4.2# docker ps --format='{{.Names}}'test-envtest-argstest-run输出所有容器名包含test的容器,并打印容器名sh-4.2# docker ps -f name=test --format='{{.Names}}'test-envtest-argstest-run查看退出状态的容器,并打印容器名sh-4.2# docker ps -f status=exited --format="{{.Names}}"thirsty_brahmaguptaclever_mestorfhopeful_morsestoic_morseelated_williamstender_jepsenreverent_mirzakhani删除所有容器:sh-4.2# docker rm -f -v $(docker ps -a -q)删除/启动所有退出的容器:sh-4.2# docker rm/start $(docker ps -qf status=exited)删除所有镜像:sh-4.2# docker rmi $(docker images -q)查看悬挂镜像:sh-4.1# docker  images -qf dangling=true只查看镜像或者容器指定的信息(在docker1.10之后才支持的)只列出镜像的id以及仓库名称:sh-4.2# docker images --format "{{.ID}}: {{.Repository}}"67591570dd29: centos0a18f1c0ead2: rancher/server只列出容器的相关id,image,status和namesh-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

注意:其实上面的--format利用的就是go语言中的模版语法,所有容器的组织信息都在结构体中:

*formatter.containerContext

容器label的使用

在实际运维过程中,大量的容器可能会一些运维上的挑战,通过使用label,可以很好的将容器分类。label贯穿于docker的整个过程。
这个label可以作为你区分业务,区分模板各种区分容器的标识,通过标识,可以将容器更好的进行分组

sh-4.2# docker run -itd --name volume-test --storage-opt size=70G --label zone=test 172.25.46.9:5001/centos6.8-jdjr-test-appc3772397e58e663095c2c0fd8d688b3d41b494097999ec2b6d6b7c509d23a138创建容器的时候定义一个label,表示该容器在test这个区域使用定义的label进行快速检索容器,并进行下一步操作(比如删除啦,更新啦)sh-4.2# docker ps -qf label=zone=testc3772397e58esh-4.2# docker ps -f label=zone=test --format='{{.Names}}'volume-test

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

查看容器的devicemapper设备:sh-4.2# docker inspect -f '{{.GraphDriver.Data.DeviceName}}' nginx docker-8:1-67411759-7c9d6d3327b02659c81bcb70bf6a4c7a45df6a589af2a2d42a387dc0e90d4913查看容器的PID:sh-4.2# docker inspect -f '{{.State.Pid}}' nginx 27521查看容器name:sh-4.2# docker inspect -f '{{.Name}}' nginx /nginx获取容器的ID:sh-4.2# docker inspect --format {{.Id}} nginx53214bc9cd001f2c548edcce0c42fe51f1a118c08941406d43122a8348055843

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

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

sh-4.2# alias dockerrm='docker rm -f -v'sh-4.2# alias dockerexec='docker exec -it'sh-4.2# alias dockerrmimage='docker rmi'sh-4.2# dockerrm volume-testvolume-testsh-4.2# dockerexec volume-test lsbin   dev  export  lib    media  opt   root  selinux  sys  usrboot  etc  home    lib64  mnt    proc  sbin  srv      tmp  varsh-4.2# dockerexec volume-test bashbash-4.1# 

使容器随着docker daemon的启动一同启动

docker run 的时候加参数--restart=always

如何动态修改容器的内存和cpu限制docker1.10之后才支持的动态调整

sh-4.2# dockerexec test-env cat /sys/fs/cgroup/memory/memory.limit_in_bytes9223372036854775807sh-4.2# cat /sys/fs/cgroup/memory/memory.limit_in_bytes 9223372036854775807可以看到,默认没有给容器限制内存,它会共享宿主机的所有内存动态调整内存为2014M:sh-4.2# docker update -m 2014M test-envtest-envsh-4.2# dockerexec test-env cat /sys/fs/cgroup/memory/memory.limit_in_bytes2111832064

docker容器中真实用户的隔离

注意:默认docker容器内部的用户会继承宿主机的用户id,也就是说容器外部有一个uid为500的用户test,容器内部有一个uid为500的用户admin,容器内部运行的程序如果在宿主机上查看的时候会发现程序的启动用户会是外部宿主机的test用户。
这是因为默认情况下容器的 user namespace 并未开启,所以容器内的用户和宿主用户共享 uid 空间。容器内的 uid 为 0 的 root,就被系统视为 uid=0 的宿主 root,因此磁盘读写时,具有宿主 root 同等读写权限。

开启user namespace:启动docker的时候加参数--userns-remap=defaulthttps://docs.docker.com/engine/reference/commandline/dockerd/#/daemon-user-namespace-options

在docker container和物理机中双向拷贝文件

容器内部文件拷贝到宿主机:sh-4.2# docker cp jupyter-70002111:/home/70002111/教程-研究功能介绍.ipynb .sh-4.2# lsDockerfile  教程-研究功能介绍.ipynb宿主机文件拷贝到容器:sh-4.2# docker cp Dockerfile jupyter-70002111:/home/70002111/sh-4.2# docker exec -it jupyter-70002188 ls Dockerfile

向容器内部程序发送signal

注意:在给容器进程发送SIGTERM信号时只会发给主进程,也就是容器内 PID 为 1 的进程。至于说主进程启动的那些子进程,完全看主进程是否愿意转发SIGTERM 给子进程了。所以那些把 Docker当做虚拟机用的,主进程跑了个bash,然后exec 进去启动程序的,或者来个&让程序跑后台的情况,应用进程必然无法收到SIGTERM。
</br>还有一种可能是在Dockerfile中的CMD那行用的是 shell 格式写的命令,而不是 exec 格式。在镜像中使用CMD启动的容器会加一个 sh -c 来去执行,因此使用 shell 格式写 CMD 的时候,PID 为 1 的进程是 sh,而它不转发信号,所以主程序收不到。

所以在写CMD哪行命令的时候,最好按照exec格式去写。

划重点: 由于在容器内部是没有init进程的,所以容器的整个生命周期会和容器内部PID为1的进程紧密相连,用户在使用过程中经常会发现容器更新版本之后,业务调用方经常会有一些请求异常,这其实也是因为容器内部的1号进程的设置有关,导致容器在停止时可能直接发送SIGKILL信号,导致容器当前正在处理中的业务也会立即断开连接,这样可能会导致一些业务异常

总而言之,向容器内部程序发送合适的信号是非常有必要的,这样可以使你的容器很优雅的退出。docker stop操作会让容器在10s后进行优雅的退出

如何优雅的关闭容器

容器的cache不释放

$ echo 1 > /proc/sys/vm/drop_caches

桥接网络连入下层网络并使用IPAM (没有NAT/端口映射)

注意:docker network是1.12版本加进来的,支持了多种网络插件

$ docker network create     -d bridge     --subnet=192.168.57.0/24     --ip-range=192.168.57.32/28     --gateway=192.168.57.11     --aux-address DefaultGatewayIPv4=192.168.57.1     -o com.docker.network.bridge.name=brnet     brnet$ brctl addif brnet eth2$ docker run --net=brnet -it busybox ifconfig注意其它主机的 --ip-range 和 --gateway 需要做对应调整。这种拓扑是,容器内 eth0 连接 brnet 接口,该接口直接通过 eth2 访问交换。

Docker查看某个容器绑定的cpu内核

容器内部第一个进程编号一般为1

$ docker exec -it container-name taskset -c -p 1 pid 1's current affinity list:0-3

给docker配置hosts

$ docker run --add-host biaoge-ops:192.168.0.1 centos cat /etc/hosts127.0.0.1   localhost::1 localhost ip6-localhost ip6-loopbackfe00::0 ip6-localnetff00::0 ip6-mcastprefixff02::1 ip6-allnodesff02::2 ip6-allrouters192.168.0.1 biaoge-ops10.0.0.3    6ff3ea7114b4

查看容器大小

$ sudo  docker ps -sCONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                     NAMES               SIZE11b6cd007b26        finance/mysql5-1    "/usr/bin/mysqld_safe"   22 months ago       Up 3
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Docker 镜像构建保姆级入门实战指南
容器技术(三)base镜像【5】
Docker
手把手教你写Docker
Docker镜像的内部结构(四)
Docker常用命令
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服