Docker Tips & Tricks

Docker Info

1
2
3
4
容器技术的核心功能,就是通过约束和修改进程的动态表现,从而为其创造出一个“边界”

Cgroups技术是用来制造约束的主要手段
Namespace技术则是用来修改进程试图的主要方法

Docker architecture

Docker uses a client-server architecture.

docker architecture

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Docker 仓库操作
docker pull/push

# Docker 镜像管理
docker images/rmi/build

# Docker 生命周期管理
docker run/start/stop/rm

# to delete all containers including its volumes use,
$ docker rm -vf $(docker ps -a -q)

# to delete all Docker images
$ docker rmi $(docker images -q)

# stop all Docker containers
> docker ps -- list all running containers
> -q flag will only list the IDs for those containers
$ docker kill $(docker ps -q)

# Remove all Docker containers
$ docker rm $(docker ps -a -q)

Docker Tips

  • Docker Tip #1: Docker 容器进程

    A Docker container is just a process/service that runs directly on your machine. It is slightly different than a regular process because the Docker daemon along with the linux kernel do a few things(CgroupsNamespace) to ensure it runs in total isolation
    Docker容器是一种特殊的进程,和虚拟机差别很大

  • Docker Tip #2: COPY vs. ADD in a Dockerfile

    COPY 和 ADD 功能很相似,都可以从指定目录拷贝数据到Docker镜像中.

    1
    2
    3
    4
    # COPYADD 区别
    1. COPY: 只能从本机文件或目录中拷贝到镜像中
    2. ADD: 不仅可以从本机文件或目录中拷贝,还可以使用URL引入外部的文件地址拷贝到镜像中
    $ ADD rootfs.tar.gz /
  • Docker Tip #3: 追加 Docker Run 指令减少镜像大小

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # Before Dockerfile -- 新增三个层lager
    RUN wget -O myfile.tar.gz http://example.com/myfile.tar.gz
    RUN tar -xvf myfile.tar.gz -C /usr/src/myapp
    RUN rm myfile.tar.gz

    # After Dockerfile -- 新增一个层layer
    RUN wget -O myfile.tar.gz http://example.com/myfile.tar.gz \
    && tar -xvf myfile.tar.gz -C /usr/src/myapp \
    && rm myfile.tar.gz
  • Docker Tip #4: Docker Base镜像OS和Host OS没有关系

    1
    2
    3
    Docker Image OS: 定义在Dockerfile文件的Base镜像的系统
    Host OS: 运行Docker image的环境
    You can use whatever base image you want for your Docker images.
  • Docker Tip #5: 使用相同Base镜像的好处

    1
    You could use a different base OS for each Docker image, but then you lose out on the ability to cache it across all of your images
  • Docker Tip #6: RUN vs. CMD in a Dockerfile

    1
    2
    3
    RUN: 在镜像内执行命令,这些指令仅仅在构建build镜像中执行一次,并且将构建结果写入新larger层中.
    CMD: 在启动容器时定义默认的运行的指令, 这种动作发生运行时run-time, 覆盖方式
    ENTRYPOINT: 执行命令参数追加方式
  • Docker Tip #7: Base Docker Image Alpine

    1
    2
    3
    Why Alpine?
    > Small. Simple. Secure. Alpine Linux is a security-oriented, lightweight Linux distribution based on musl libc and busybox.
    > Alpine is about 30x smaller than Debian.
  • Docker Tip #8: Project Structure with Multiple Dockerfiles and Docker Compose

    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
    ubuntu in ~/chyi/micro-services at 3BPlus on 🐳 v20.10.8
    ➜ tree -L 2
    .
    ├── auth
    │   └── Dockerfile
    ├── billing
    │   └── Dockerfile
    ├── contact
    │   └── Dockerfile
    ├── docker-compose.yml
    └── user
    └── Dockerfile

    4 directories, 5 files

    The docker-compose.yaml
    ubuntu in ~/chyi/micro-services at 3BPlus on 🐳 v20.10.8
    cat docker-compose.yml
    version: '3'

    services:
    auth:
    build: './auth'
    billing:
    build: './billing'
    contact:
    build: './contact'
    user:
    build: './user'
  • Docker Tip #9: 使用Volumes

    1
    2
    3
    4
    5
    6
    # docker-compose.yaml
    services:
    app:
    # Mount the crrent directoy into `/app` inside the running container.
    volumes:
    - '.:/app'
  • Docker Tip #10: Published Ports

    Creates a firwaall rule which maps a container port to a port on the Docker host to the outside world.

Flag value Description
-p 8080:80 Map TCP port 80 in the container to port 8080 on the Docker host.
-p 192.168.1.100:8080:80 Map TCP port 80 in the container to port 8080 on the Docker host for connections to host IP 192.168.1.100.
-p 8080:80/udp Map UDP port 80 in the container to port 8080 on the Docker host.
-p 8080:80/tcp -p 8080:80/udp Map TCP port 80 in the container to TCP port 8080 on the Docker host, and map UDP port 80 in the container to UDP port 8080 on the Docker host.
  • Docker Tip #11: dockerignore file

    1
    2
    3
    .dockerignore: ignore certain files and folders from your Docker images
    .git
    .dockerignore
  • Docker Tip #12: Manage Docker without sudo on Linux

    1
    2
    3
    # Add a docker group and then add your user to it:
    $ sudo groupadd docker
    $ docker usermod -aG docker $USER
  • Docker Tip #13: Measure Docker Container’s Resources

    How much resources containers are using

    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
    $ docker stats
    CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
    298d90f942e1 k8s_POD_kafka-zookeeper-0_default_a243d677-101b-493b-a076-d94f46785f22_0 0.00% 724KiB / 3.704GiB 0.02% 0B / 0B 0B / 0B 1
    1d92a13e4a6f k8s_POD_kafka-0_default_f7374645-9904-436c-bc8d-43ed415833c1_0 0.00% 872KiB / 3.704GiB 0.02% 0B / 0B 0B / 0B 1
    b638c1bbd855 k8s_POD_postgres-postgresql-0_infrastructure_d9067ee1-6874-4018-a008-09362ad9330d_16 0.00% 868KiB / 3.704GiB 0.02% 0B / 0B 0B / 0B 1
    0fdc76799b4e k8s_kube-flannel_kube-flannel-ds-nk6tj_kube-system_0a186e7a-c0d7-4282-9f5d-65ee20d0e13a_12 0.07% 15.4MiB / 50MiB 30.80% 0B / 0B 33.1MB / 0B 11
    4c3705247efa k8s_kube-proxy_kube-proxy-xwfvl_kube-system_f46216cb-d018-4d82-b510-9be5e01cefca_12 0.00% 23.36MiB / 3.704GiB 0.62% 0B / 0B 43.7MB / 12.3kB 8
    16d5db1e7447 k8s_POD_kube-proxy-xwfvl_kube-system_f46216cb-d018-4d82-b510-9be5e01cefca_13 0.00% 1.996MiB / 3.704GiB 0.05% 0B / 0B 487kB / 0B 1
    496aacf5fddf k8s_POD_kube-flannel-ds-nk6tj_kube-system_0a186e7a-c0d7-4282-9f5d-65ee20d0e13a_13 0.00% 768KiB / 3.704GiB 0.02% 0B / 0B 0B / 0B 1
    1e328afeb116 dapr_zipkin 0.17% 250.2MiB / 3.704GiB 6.60% 18MB / 0B 60MB / 0B 55
    27872f88cae3 dapr_placement 0.11% 5.992MiB / 3.704GiB 0.16% 18MB / 0B 13.6MB / 0B 10
    27c1f6daa81c dapr_redis 0.35% 5.633MiB / 3.704GiB 0.15% 18MB / 0B 10.7MB / 0B 5

    $ docker stats --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}"
    CONTAINER CPU % MEM USAGE / LIMIT
    298d90f942e1 0.00% 724KiB / 3.704GiB
    1d92a13e4a6f 0.00% 872KiB / 3.704GiB
    b638c1bbd855 0.00% 868KiB / 3.704GiB
    0fdc76799b4e 2.37% 15.42MiB / 50MiB
    4c3705247efa 0.00% 23.36MiB / 3.704GiB
    16d5db1e7447 0.00% 1.996MiB / 3.704GiB
    496aacf5fddf 0.00% 768KiB / 3.704GiB
    1e328afeb116 0.21% 250.2MiB / 3.704GiB
    27872f88cae3 0.12% 5.992MiB / 3.704GiB
    27c1f6daa81c 0.34% 5.633MiB / 3.704GiB
  • Docker Tip #14: Docker Compose vs Docker Stack

    1
    2
    3
    # Docker Compose: is an official tool that helps you manage your Docker containers by letting you define everything through a docker-compose.yml file.

    # docker stack: is a command that's embedded into the Docker CLI. Lets you manage a cluster of Docker containers through Docker Swarm.
  • Docker Tip #15: Metadata Docker Images with Labels

    1
    2
    3
    4
    5
    6
    7
    8
    # Dockerfile example of adding 2 labels with 1 LABEL instruction:
    LABEL <key>=<value>
    LABEL version="1.0" maintainer="chyi <nick.chyi@gmail.com>"

    # Docker build example to add dynamic labels to your Docker images:
    $ docker build . --label "version=1.0" --label "maintaner=chyi <nick.chyi@gmail.com>"

    # docker inspect images
  • Docker Tip #16: Named Volumes vs Path Based Volumes

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # Named volumes
    postgres:/var/lib/postgresql/data

    docker-compose automatically create the postgres volume, if not you could running __$ docker volume create postgres__.
    On Linux, the volume will get saved to /var/lib/docker/volumes/postgres/_data

    # Path based volumes
    ./postgres:/var/lib/postgresql/data

    postgres/ directory would get created in the current directory on the Docker host.
  • Docker Tip #17: The Volume or Mount Flag

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # Setting up a volume the old way with docker run:
    $ docker container run … -v "$(pwd)":/myapp

    # Setting up the same volumes using the mount flag with docker run:
    $ docker container run … --mount type=bind,source="$(pwd)",target=/myapp

    # Docker compose
    volumes:
    - type: "bind"
    source: "."
    target: "/myapp"
  • Docker Tip #18: Connect to a Service Running on Docker Host

    Implementation of connecting to Docker host over a custom network with a static IP address.

    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
    41
    42
    # Create a custom bridge Docker network
    ubuntu in ~ at 3BPlus
    ➜ docker network create -d bridge --subnet 192.168.0.0/24 --gateway 192.168.0.1 mynet
    0330b879fcc8fb23eeb092cb66fd86f1796e7f0abe37df4978903cf8fd07217b

    ubuntu in ~ at 3BPlus
    ➜ ifconfig
    br-0330b879fcc8: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
    inet 192.168.0.1 netmask 255.255.255.0 broadcast 192.168.0.255
    ether 02:42:16:0c:c0:51 txqueuelen 0 (Ethernet)
    RX packets 0 bytes 0 (0.0 B)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 0 bytes 0 (0.0 B)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

    # Start the Alpine container and drop into a Shell prompt.
    ubuntu in ~ at 3BPlus
    ➜ docker container run --rm -it alpine sh

    # Install the ping utility.
    / # apk update && apk add iputils
    fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/main/aarch64/APKINDEX.tar.gz
    fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/community/aarch64/APKINDEX.tar.gz
    v3.14.2-5-gd4163d4c6c [https://dl-cdn.alpinelinux.org/alpine/v3.14/main]
    v3.14.2-4-ga15b4dc067 [https://dl-cdn.alpinelinux.org/alpine/v3.14/community]
    OK: 14810 distinct packages available
    (1/2) Installing libcap (2.50-r0)
    (2/2) Installing iputils (20210202-r0)
    Executing busybox-1.33.1-r3.trigger
    OK: 6 MiB in 16 packages

    # Ping the custom IP address we set up.
    / # ping 192.168.0.1

    # You should see this output (hit CTRL+C to stop it)
    PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
    64 bytes from 192.168.0.1: icmp_seq=1 ttl=64 time=0.336 ms
    64 bytes from 192.168.0.1: icmp_seq=2 ttl=64 time=0.293 ms
    ^C
    --- 192.168.0.1 ping statistics ---
    2 packets transmitted, 2 received, 0% packet loss, time 1013ms
    rtt min/avg/max/mdev = 0.293/0.314/0.336/0.021 ms
  • Docker Tip #19: Show Total Disk Space Used by Docker

    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
    ubuntu in ~ at 3BPlus
    ➜ docker system df
    TYPE TOTAL ACTIVE SIZE RECLAIMABLE
    Images 3 2 203.9MB 198.5MB (97%)
    Containers 3 1 2.524MB 0B (0%)
    Local Volumes 1 0 0B 0B
    Build Cache 0 0 0B 0B

    # -v flag (verbose) - will show the unique image size for each image
    ubuntu in ~ at 3BPlus
    ➜ docker system df -v
    Images space usage:

    REPOSITORY TAG IMAGE ID CREATED SIZE SHARED SIZE UNIQUE SIZE CONTAINERS
    alpine latest bb3de5531c18 4 days ago 5.337MB 0B 5.337MB 2
    hello-world latest bc11b176a293 7 weeks ago 9.136kB 0B 9.136kB 1
    bahamat/unix-1st-ed latest 37aa142d2113 5 years ago 198.5MB 0B 198.5MB 0

    Containers space usage:

    CONTAINER ID IMAGE COMMAND LOCAL VOLUMES SIZE CREATED STATUS NAMES
    9023720cdee7 alpine "sh" 0 2.52MB 5 hours ago Up 5 hours upbeat_kepler
    9e272ab58362 alpine "sh -c 'exit 1'" 0 0B 6 hours ago Exited (1) 6 hours ago naughty_blackburn
    d95cc7e19d43 hello-world "/hello" 0 0B 7 weeks ago Exited (0) 7 weeks ago nifty_hellman

    Local Volumes space usage:

    VOLUME NAME LINKS SIZE
    user_my-db 0 0B

    Build cache usage: 0B

    CACHE ID CACHE TYPE SIZE CREATED LAST USED USAGE SHARED
  • Docker Tip #20: Docker Compose Stop vs Down

    1
    2
    3
    4
    5
    6
    7
    8
    # docker-compose stop
    > stop container, but it won't remove them

    # docker-compose down
    > stop container, removes the stopped containers as well as any networks that were created.

    # docker-compose down -v
    > add remove all volumes too.
  • Docker Tip #21: Difference between Docker Create, Start and Run

    1
    2
    3
    4
    5
    6
    7
    8
    # Create:
    adds a writeable container on top of your image and sets it up for running whatever command you specified in you CMD. The container ID is reported back but it's not started.

    # Start:
    will start any stopped container.

    # Run:
    combination of create and start, It creates the container and starts it.
  • Docker Tip #22: Docker Mem Limit

    1
    2
    > 默认情况下容器使用的资源不受限制,可以使用主机内核调度器所允许的最大资源
    > 限制容器不能过多的使用主机的内存,一旦内存检测到没有足够的内存可以分配,就会出现OOM(Out Of Memory Exception). 并开始随机Kill一些进程用于释放内存空间,docker尝试调整docker daemon 的OOM优先级进行缓解,内核在选择杀死的进程时会对所有的进程打分,直接杀死得分最高的进程,docker daemon的OOM优先级被降低
    • show_process_score.sh
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      # 脚本输出得分最高的10个进程,并排序
      ➜ ./show_process_score.sh
      672 1510 /usr/bin/gnome-shell
      669 1811 /usr/libexec/gnome-initial-setup --existing-user
      668 1010 /usr/lib/xorg/Xorg vt2 -displayfd 3 -auth /run/use
      667 2062 update-notifier
      667 1760 /usr/libexec/evolution-data-server/evolution-alarm
      667 1128 /usr/libexec/goa-daemon
      666 996 /usr/libexec/tracker-miner-fs
      666 994 /usr/bin/pulseaudio --daemonize=no --log-target=jo
      666 988 (sd-pam)
      666 987 /lib/systemd/systemd --user

      # 降低OOM风险:
      - 通过测试掌握应用对内存的需求
      - 保证运行容器的主机有充足的内存
      - 限制容器可以使用的内存
      - 为主机配置Swap

    • 压力测试工具 stress
      1
      2
      # stress
      > a tool for generating workload. It can produce CPU, memory, I/O, and disk stress.
    • stress.Dockerfile
      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
      # 创建镜像
      ➜ docker build -f stress.Dockerfile -t chyiyaqing/u-stress:latest .

      # 限制内存使用上限(memory-swap值包含容器可用内存和可用swap;)
      ➜ docker run -it -m 300M --memory-swap -1 --name con1 chyiyaqing/u-stress /bin/bash
      root@1a3df043e956:/# stress --vm 1 --vm-bytes 500M
      stress: info: [9] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd

      # docker stats 查看
      $ docker stats
      CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
      1a3df043e956 con1 71.85% 300MiB / 300MiB 100.00% 6.71kB / 0B 3.45GB / 0B 3

      # Top命令查看stress进程内存实际情况
      chyiyaqing in ~ at chyiyaqing-PowerEdge-R720 took 5s
      # pgrep 命令查询stress命令相关进程
      ➜ pgrep stress
      48622
      48623

      chyiyaqing in ~ at chyiyaqing-PowerEdge-R720
      ➜ top -p 48623
      top - 22:40:23 up 2 days, 5:40, 4 users, load average: 0.95, 0.47, 0.18
      Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie
      %Cpu(s): 0.1 us, 2.0 sy, 0.0 ni, 97.1 id, 0.8 wa, 0.0 hi, 0.0 si, 0.0 st
      MiB Mem : 32106.2 total, 27283.4 free, 1420.6 used, 3402.2 buff/cache
      MiB Swap: 2048.0 total, 1545.3 free, 502.7 used. 30224.1 avail Mem

      PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
      48623 root 20 0 515868 305460 272 R 71.7 0.9 2:02.53 stress

      # VIRT 进程虚拟内存大小; RES 实际分配物理内存大小
  • Docker Tip #23: Docker CPU Limit

    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
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    > 默认情况下容器可以不受限制的使用CPU/内存资源, 如果不对容器使用进行限制,一旦发生容器程序异常使用CPU/Mem情况,可能会把整个主机CPU/Mem资源耗尽.

    # 限制可用CPU个数
    ➜ docker run --rm -it --cpus=2 chyiyaqing/u-stress /bin/bash

    root@f11127fe7c50:/# stress -c 4
    stress: info: [9] dispatching hogs: 4 cpu, 0 io, 0 vm, 0 hdd

    # docker stats
    CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
    f11127fe7c50 competent_noether 198.98% 1.695MiB / 31.35GiB 0.01% 39.7kB / 0B 0B / 0B 6

    # Top
    Tasks: 468 total, 5 running, 463 sleeping, 0 stopped, 0 zombie
    %Cpu0 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu1 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu2 : 50.0 us, 0.0 sy, 0.0 ni, 50.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st --
    %Cpu3 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu4 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu5 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu6 : 5.0 us, 5.0 sy, 0.0 ni, 90.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu7 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu8 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu9 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu10 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu11 : 50.0 us, 0.0 sy, 0.0 ni, 50.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st --
    %Cpu12 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu13 : 47.4 us, 0.0 sy, 0.0 ni, 52.6 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st --
    %Cpu14 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu15 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu16 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu17 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu18 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu19 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu20 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu21 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu22 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu23 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu24 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu25 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu26 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu27 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu28 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu29 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu30 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu31 : 50.0 us, 0.0 sy, 0.0 ni, 50.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st --
    MiB Mem : 32106.2 total, 27901.2 free, 1119.0 used, 3086.0 buff/cache
    MiB Swap: 2048.0 total, 2044.6 free, 3.4 used. 30537.0 avail Mem

    查看Top真实情况不是两个CPU负载100%, 而是容器消耗CPU总共200%的负载,进程没有CPU数的限制,只能通过进程消耗CPU时间片统计出进程占用CPU的百分比

    # 指定固定CPU
    > 通过--cpuset-cpus设置容器运行在几个固定的CPU上, 因为多核系统每个核心都有自己的缓存,频繁的调度进程在不同的核心上执行会带来缓存失效的开销
    chyiyaqing in ~ at chyiyaqing-PowerEdge-R720
    ➜ docker run --rm -it --cpuset-cpus="0,1,2,3" chyiyaqing/u-stress /bin/bash

    # 启动塔里测试命令
    root@95110b6915af:/# stress -c 10
    stress: info: [12] dispatching hogs: 4 cpu, 0 io, 0 vm, 0 hdd

    # docker stats
    CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
    39b4ce536148 frosty_stonebraker 399.38% 2.43MiB / 31.35GiB 0.01% 3.9kB / 0B 0B / 0B 12

    # Top
    ➜ top
    top - 23:08:19 up 2 days, 6:08, 4 users, load average: 6.97, 3.73, 2.01
    Tasks: 496 total, 11 running, 485 sleeping, 0 stopped, 0 zombie
    %Cpu0 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu1 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu2 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu3 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu4 : 0.0 us, 0.0 sy, 0.0 ni, 97.7 id, 0.0 wa, 0.0 hi, 2.3 si, 0.0 st

    # 设置CPU的权重
    > 设置CPU权重只有在容器争用CPU资源的情况下,CPU的权重才能让不同的容器分到不同的CPU用量 --cpu-shares 设置CPU权重,默认值为1024,

    # 运行两个容器,指定使用CPU0,分别设置--cpu-shares 512,1024
    ➜ docker run --rm -it --cpuset-cpus="0" --cpu-shares=512 chyiyaqing/u-stress /bin/bash
    ➜ docker run --rm -it --cpuset-cpus="0" --cpu-shares=1024 chyiyaqing/u-stress /bin/bash

    # 两个容器都运行stress -c 4

    # top
    ➜ top
    top - 23:14:14 up 2 days, 6:14, 5 users, load average: 5.30, 5.25, 3.42
    Tasks: 495 total, 9 running, 486 sleeping, 0 stopped, 0 zombie
    %Cpu0 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
    %Cpu1 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st

    # docker stats
    CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
    f9c8864fab87 beautiful_neumann 66.39% 1.695MiB / 31.35GiB 0.01% 5.23kB / 0B 0B / 0B 6
    6b69afc7fea5 pensive_vaughan 33.41% 1.676MiB / 31.35GiB 0.01% 7.17kB / 0B 0B / 0B 6
  • Docker Tip #24: Docker import/export vs. load/save

    1
    2
    3
    4
    5
    ➜ docker --help | grep -E "(export|import|load|save)"
    export Export a container's filesystem as a tar archive
    import Import the contents from a tarball to create a filesystem image
    load Load an image from a tar archive or STDIN
    save Save one or more images to a tar archive (streamed to STDOUT by default)
  • Docker Tip #25: Docker网络模式

    Docker 网络模式 配置 说明
    host模式 -net=host 容器和宿主机共享Network namespace
    container 模式 -net=container:NAME_or_ID 容器与另外一个容器共享Network namespace, kubernetes中的pod就是多个容器共享一个Network namespace
    none模式 -net=none 容器有独立的Network namespace,但并没有对其进行任何网络设置
    bridge模式 -net=bridge 默认为该模式
    1
    2
    3
    4
    # 实现原理
    > 宿主机虚拟一个Docker容器网桥(docker0), Docker启动一个容器时会根据Docker网桥(docker0)的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关.因为同一宿主机内的容器都接入同一网桥,这样容器之间就能够通过容器的Container-IP直接通信.
    > Docker网桥是宿主主机虚拟出来的,并不是真是存在的网络设备,外部网络是无法寻址到,如果容器希望外部能够访问到,可以通过映射容器端口到宿主主机(端口映射),访问容器的时候就通过[宿主主机IP]:[容器端口]访问容器

    • host模式
      Host模式
      1
      2
      > 容器使用host模式将使用宿主主机的IP和端口,容器的其他方面,文件系统、进程列表还是和宿主主机隔离
      > 使用host模式的容器可以直接使用宿主主机的IP地址与外界通信,容器内部的服务端口也可以使用宿主主机的端口,不需要进行NAT,host最大优势是网络性能比较好,但是docker host上已经使用的端口就不能再使用,网络隔离型不好
    • container模式
      Container模式
      1
      > 新创建的容器和已经存在的一个容器共享一个Network Namespace.新创建的容器不会创建自己的网卡,配置自己的IP,而是和指定的容器共享IP和端口范围, 两个容器的进程可以通过lo网卡设备通信
    • none模式
      None模式
      1
      2
      > None模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置,Docker容器没有网卡、IP、路由,需要自己对Docker容器添加网卡、配置IP
      > None模式下只有lo回环网络,没有其他网卡,None模式可以在容器创建时通过network=None指定,这类网络没办法联网,封闭的网络能很好的保证容器的安全
    • bridge模式
      Bridge模式
      1
      > bridge模式是docker默认网络模式,不写--net参数就是bridge模式
  • Docker Tip #26: Alphine Linux Dockerfile

    1
    2
    3
    4
    5
    6
    chyiyaqing in core at chyiyaqing-PowerEdge-R720 on  feat/adaptation-kingbases [!?] via 🐹 v1.17.1 on 🐳 v20.10.10
    ➜ docker run core:BF-9748
    Error relocating /root/core/blocface-core: __vfprintf_chk: symbol not found
    Error relocating /root/core/blocface-core: __fprintf_chk: symbol not found

    在Alpine Linux上, not found错误是动态链接失败的典型特征,musl的ldd链接器存在一个相当混乱的错误,大多数Linux软件都是与glibc(GNUlibc库)相链接(libc提供了标准的C库和posixapi),大多数Linux发行版本都是基于glibc, alpineLinux是基于muslibc库(这是最小的实现,严格遵守POSIX).
  • Docker Tip #27: 防止容器自动退出

    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
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    > docker容器的生命周期是同容器中的前置进程相关在一起,前置进程运行结束后,容器便自动退出

    下文使用alpine镜像做为基础镜像,创建一个alpine系统小容器,让其可以常驻运行,以便我们登陆交互执行

    # 使用alpine系统镜像创建容器
    # -i interactive=true 开启stdin
    # -t tty=true 分配会话终端
    # -d 守护模式 不加就直接进入容器中需要ctrl+p+q切出,

    chyiyaqing in ~ at chyiyaqing-PowerEdge-R720 took 9s
    ➜ docker run -it -d --name my_alpine alpine sh
    Unable to find image 'alpine:latest' locally
    latest: Pulling from library/alpine
    a0d0a0d46f8b: Pull complete
    Digest: sha256:e1c082e3d3c45cccac829840a25941e679c25d438cc8412c2fa221cf1a824e6a
    Status: Downloaded newer image for alpine:latest
    78c0429dd98fe42addaa2071ffe1ca6c22295ea6d6d465ff1f970644f6234a37

    # my_alpine 容器处于运行状态
    chyiyaqing in ~ at chyiyaqing-PowerEdge-R720 took 8s
    ➜ docker ps | grep alpine
    78c0429dd98f alpine "sh" 34 seconds ago Up 34 seconds my_alpine

    # 登入容器
    chyiyaqing in ~ at chyiyaqing-PowerEdge-R720
    ➜ docker exec -it my_alpine sh

    # 查看 sh 会话数量
    / # ps
    PID USER TIME COMMAND
    1 root 0:00 sh
    7 root 0:00 sh
    13 root 0:00 ps

    # alpine使用apk做为包管理
    / # apk add sl
    fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/main/x86_64/APKINDEX.tar.gz
    fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/community/x86_64/APKINDEX.tar.gz
    (1/3) Installing ncurses-terminfo-base (6.2_p20210612-r0)
    (2/3) Installing ncurses-libs (6.2_p20210612-r0)
    (3/3) Installing sl (5.02-r0)
    Executing busybox-1.33.1-r3.trigger
    OK: 6 MiB in 17 packages
    / # sl
    (@@@@)

    ( )
    ==== ________ ___________
    _D _| |_______/ \__I_I_____===__|_________|
    |(_)--- | H\________/ | | =|___ ___| _________________
    / | | H | | | | ||_| |_|| _| \_____A
    | | | H |__--------------------| [___] | =| |
    | ________|___H__/__|_____/[][]~\_______| | -| |
    |/ | |-----------I_____I [][] [] D |=======|____|________________________|_
    __/ =| o |=-~O=====O=====O=====O\ ____Y___________|__|__________________________|_
    |/-=|___|= || || || |_____/~\___/ |_D__D__D_| |_D__D__D_|
    \_/ \__/ \__/ \__/ \__/ \_/ \_/ \_/ \_/ \_/

    # 提交容器变更生成新的镜像
    chyiyaqing in ~ at chyiyaqing-PowerEdge-R720 took 2m 57s
    ➜ docker commit -m "alpine with sl cmd" -a "big_cat" my_alpine chyiyaqing/alpine_sl
    sha256:79981bb43b0e638cc193570456ad93793a8cb481c8940e4fd899a0cc60a8bd46

    # 发布到Docker Hub
    chyiyaqing in ~ at chyiyaqing-PowerEdge-R720 took 10s
    ➜ docker push chyiyaqing/alpine_sl
    Using default tag: latest
    The push refers to repository [docker.io/chyiyaqing/alpine_sl]
    102b73ff0977: Pushed
    e2eb06d8af82: Mounted from library/alpine
    latest: digest: sha256:500e9b9536a4fec460c487867d3cd7084da934ba37151aa122f4be438cc06d57 size: 739

    # 停止/启动容器
    $ docker stop/start my_alpine
  • Docker Tip #28: Docker目录空间

    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工作根目录
    [hyperchain@mini package]$ docker info | grep 'Docker Root Dir'
    Docker Root Dir: /var/lib/docker

    # 查看工作目录占用空间大小
    [hyperchain@mini package]$ sudo du -sh /var/lib/docker/
    65G /var/lib/docker/

    # 查看docker占用磁盘空间
    [hyperchain@mini package]$ docker system df
    TYPE TOTAL ACTIVE SIZE RECLAIMABLE
    Images 22 0 11.07GB 11.07GB (100%)
    Containers 0 0 0B 0B
    Local Volumes 120 0 56.7GB 56.7GB (100%)
    Build Cache 0 0 0B 0B

    # 清理docker没有被使用的docker镜像
    [hyperchain@mini package]$ docker system prune -a
    WARNING! This will remove:
    - all stopped containers
    - all networks not used by at least one container
    - all dangling images
    - all dangling build cache
    Are you sure you want to continue? [y/N] y
    Total reclaimed space: 0B

    # 停止docker服务
    [hyperchain@mini package]$ systemctl stop docker
    ==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ====
    Authentication is required to stop 'docker.service'.
    Authenticating as: hyperchain
    Password:
    ==== AUTHENTICATION COMPLETE ====
    [hyperchain@mini package]$

    # 删除 volumnes
    [hyperchain@mini package]$ docker volume prune
    WARNING! This will remove all local volumes not used by at least one container.
    Are you sure you want to continue? [y/N] y
    Deleted Volumes:

Have a Fun

  • Run the First Edition of Unix (1972) with Docker

    Run a PDP-11 simulator through Docker to interact with Unix as it was back in 1972

    1
    $ docker run --rm -it bahamat/unix-1st-ed