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


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

    来源:http://www.jianshu.com/p/0231568ab335

    创建容器时传入环境变量

    在实际应用场景中,不论是从安全还是可配置方面去考虑,很多参数是比较适合用环境变量加载进去的,比如数据库的连接信息,时区,还有字体支持等等,在创建容器的时候其实都可以使用-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 
    ee20b44301e27c16eae63dab243d293054178dd5f819c23d44bd9e534208bb42
    sh-4.2# docker exec -it test-env date
    2017年 01月 17日 星期二 10:35:17 CST
    sh-4.2# date
    Tue 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-app
    d6a02874b999ff4eea79e3b302148b42043af01c89a5d31e5d858e0806f9077a
    sh-4.2# docker exec -it test date
    2017年 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
    指定容器的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-app
    18d47e69802aa84df00182885b256c50ebc56e15d8e6990fc1e187ffe254171e
    
    sh-4.2# docker exec -it volume-test df -H | grep rootfs
    rootfs                 76G  1.5G   74G   2% /
    sh-4.2# docker exec -it test-env df -H | grep rootfs
    rootfs                 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-env
    test-args
    test-run
    输出所有容器名包含test的容器,并打印容器名
    sh-4.2# docker ps -f name=test --format='{{.Names}}'
    test-env
    test-args
    test-run
    查看退出状态的容器,并打印容器名
    sh-4.2# docker ps -f status=exited --format="{{.Names}}"
    thirsty_brahmagupta
    clever_mestorf
    hopeful_morse
    stoic_morse
    elated_williams
    tender_jepsen
    reverent_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: centos
    0a18f1c0ead2: 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}}	{{.Image}}	{{.Status}}	{{.Names}}"
    CONTAINER ID        IMAGE                                         STATUS              NAMES
    66b60b72f00e        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-app
    c3772397e58e663095c2c0fd8d688b3d41b494097999ec2b6d6b7c509d23a138
    创建容器的时候定义一个label,表示该容器在test这个区域
    使用定义的label进行快速检索容器,并进行下一步操作(比如删除啦,更新啦)
    sh-4.2# docker ps -qf label=zone=test
    c3772397e58e
    sh-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

    使用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-test
    volume-test
    
    sh-4.2# dockerexec volume-test ls
    bin   dev  export  lib      media  opt   root  selinux  sys  usr
    boot  etc  home    lib64  mnt     proc  sbin  srv      tmp  var
    sh-4.2# dockerexec volume-test bash
    bash-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_bytes
    9223372036854775807
    sh-4.2# cat /sys/fs/cgroup/memory/memory.limit_in_bytes 
    9223372036854775807
    可以看到,默认没有给容器限制内存,它会共享宿主机的所有内存
    动态调整内存为2014M:
    sh-4.2# docker update -m 2014M test-env
    test-env
    sh-4.2# dockerexec test-env cat /sys/fs/cgroup/memory/memory.limit_in_bytes
    2111832064
    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=default
    https://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# ls
    Dockerfile  教程-研究功能介绍.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。 还有一种可能是在Dockerfile中的CMD那行用的是 shell 格式写的命令,而不是 exec 格式。在镜像中使用CMD启动的容器会加一个 sh -c 来去执行,因此使用 shell 格式写 CMD 的时候,PID 为 1 的进程是 sh,而它不转发信号,所以主程序收不到。 所以在写CMD哪行命令的时候,最好按照exec格式去写。 桥接网络连入下层网络并使用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
     
     
  • 相关阅读:
    用SQL语言操作数据
    用表组织数据
    第一个C#程序
    利用CSS3制作网页动画
    CSS3美化网页元素
    列表、表格与媒体元素
    表单
    HTML5基础
    使用Java编译思想
    Day06:方法 / 猜字母游戏
  • 原文地址:https://www.cnblogs.com/happyyftk/p/7155240.html
Copyright © 2020-2023  润新知