Docker容器


Docker 容器

简介

  • 是一个开源的应用容器引擎,让开发者可以以统一的方式打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何安装了docker引擎的服务器上(包括流行的Linux机器、windows机器),也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。
  • 启动容器的简便方式是使用docker container run命令。该命令可以携带参数,在其基础的格式docker container run 中,指定了启动所需的镜像以及要运行的应用。-it参数可以将当前终端连接到容器的Shell终端之上。容器会随着其中运行应用的退出而终止。

详解

容器vs虚拟机

  • 虚拟机:虚拟机是计算机系统的仿真。简而言之,它可以在实际上是一台计算机的硬件上运行看起来很多单独的计算机。操作系统及其应用程序从单个主机服务器或主机服务器池共享硬件资源。每个VM都需要自己的底层操作系统,并且硬件是虚拟化的。管理程序或虚拟机监视器是创建和运行VM的软件,固件或硬件。它位于硬件和虚拟机之间,是虚拟化服务器所必需的。
  • 容器:容器不虚拟化底层计算机,只是虚拟化操作系统。容器位于物理服务器及其主机操作系统之上 - 通常是Linux或Windows。每个容器共享主机操作系统内核,通常也包括二进制文件和库。共享组件是只读的。共享操作系统资源(如库)可以显着减少重现操作系统代码的需要,并且意味着服务器可以通过单个操作系统安装来运行多个工作负载。因此容器非常轻,它们只有几兆字节,只需几秒钟即可启动。与容器相比,VM需要几分钟才能运行,并且比同等容器大一个数量级。

启动容器

命令的基础格式为docker container run <options> <image>:<tag><app>。使用docker container run -it ubuntu:latest,使用ubuntu:latest镜像启动容器。@之后的一长串数字是容器唯一ID的前12个字符。

root@f7c9d1c8c556:/# ls
bin   dev  home  lib32  libx32  mnt  proc  run   srv  tmp  var
boot  etc  lib   lib64  media   opt  root  sbin  sys  usr
root@f7c9d1c8c556:/# 

使用python:latest镜像启动容器,并执行命令python3:sudo docker container run -it python:latest python3

Python 3.10.7 (main, Sep 13 2022, 14:31:33) [GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 

Docker会选择合适的API来调用Docker daemon。Docker daemon接收到命令并搜索Docker本地缓存,检查是否有命令所请求的镜像。若本地缓存并未包含该镜像,Docker接下来会查询在Docker Hub中是否存在对应镜像。找到该镜像后,Docker将镜像拉取到本地,存储在本地缓存当中。一旦镜像拉取到本地,daemon就创建容器并在其中运行指定的应用。

容器进程

sudo docker container run -it ubuntu:latest启动Ubuntu容器之时,让容器运行Bash Shell(/bin/bash)。这使得Bash Shell成为容器中运行的且唯一运行的进程。使用ps -aux查看运行的进程。

root@43599506fa9c:/# ps -aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.7  0.0   4628  3608 pts/0    Ss   10:56   0:00 bash
root           9  0.0  0.0   7060  1544 pts/0    R+   10:56   0:00 ps -aux

PID为1的进程,是运行的Bash Shell;第二个进程是ps -aux命令产生的,这是个临时进程,并且在输出后就已经退出了。容器如果不运行任何进程则无法存在,在上例中杀死Bash Shell就会杀死了容器唯一运行的进程,从而导致这个容器也被杀死。输入exit退出Bash Shell,那么容器也会退出(终止)。使用Ctrl-PQ组合键则会退出容器但并不终止容器运行。这样做会切回到Docker主机的Shell,并保持容器在后台运行。可以使用docker container ls命令来观察当前系统正在运行的容器列表。

ronie@ronie-virtual-machine:~/Desktop$ sudo docker container ls
CONTAINER ID   IMAGE           COMMAND   CREATED         STATUS         PORTS     NAMES
43599506fa9c   ubuntu:latest   "bash"    5 minutes ago   Up 5 minutes             suspicious_feynman
ronie@ronie-virtual-machine:~/Desktop$ 

容器仍在运行,且可以通过docker container exec命令将终端重新连接到Docker

ronie@ronie-virtual-machine:~/Desktop$ sudo docker container exec -it 43599 bash
root@43599506fa9c:/# 

再次使用在容器中使用ps -aux命令,会看到两个Bash进程,这是因为docker container exec命令创建了新的Bash

root@43599506fa9c:/# ps -aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  0.0   4628  3608 pts/0    Ss+  10:56   0:00 bash
root          17  0.0  0.0   4628  3776 pts/1    Ss   11:07   0:00 bash
root          25  0.0  0.0   7060  1552 pts/1    R+   11:11   0:00 ps -aux

输入exit退出容器,并通过命令docker container ps来确认容器依然在运行中,可以看到容器仍在运行中。

root@43599506fa9c:/# exit
exit
ronie@ronie-virtual-machine:~/Desktop$ sudo docker container ls
CONTAINER ID   IMAGE           COMMAND   CREATED          STATUS          PORTS     NAMES
43599506fa9c   ubuntu:latest   "bash"    17 minutes ago   Up 17 minutes             suspicious_feynman
ronie@ronie-virtual-machine:~/Desktop$ 

若要停止或删除容器,可以使用以下两个命令

ronie@ronie-virtual-machine:~/Desktop$ sudo docker container ls
CONTAINER ID   IMAGE           COMMAND   CREATED          STATUS          PORTS     NAMES
8a797751d4c7   ubuntu:latest   "bash"    11 seconds ago   Up 10 seconds             jolly_blackwell
ronie@ronie-virtual-machine:~/Desktop$ sudo docker container stop 8a79
8a79
ronie@ronie-virtual-machine:~/Desktop$ sudo docker container rm 8a79
8a79

容器生命周期

停止容器运行并不会损毁容器或者其中的数据,现在我们新建一个容器并运行它,并创建一个文件向其中写入数据

ronie@ronie-virtual-machine:~/Desktop$ sudo docker run --name ronie -it ubuntu:latest
root@b14543669b85:/# touch myfile
root@b14543669b85:/# echo 'test data' > myfile
root@b14543669b85:/# cat myfile 
test data
root@b14543669b85:/# 

使用Ctrl-PQ组合键退出当前容器。再使用docker container stop命令暂停容器。(docker container ls命令列出全部处于运行状态的容器。使用docker container ls -a列出全部容器。)

ronie@ronie-virtual-machine:~/Desktop$ sudo docker container stop b14
b14
ronie@ronie-virtual-machine:~/Desktop$ sudo docker container ls -a
CONTAINER ID   IMAGE           COMMAND   CREATED         STATUS                        PORTS     NAMES
b14543669b85   ubuntu:latest   "bash"    5 minutes ago   Exited (137) 58 seconds ago             ronie

现在使用docker container start命令将容器重新启动并使用docker container exec连接容器。

ronie@ronie-virtual-machine:~/Desktop$ sudo docker container start ronie
ronie
ronie@ronie-virtual-machine:~/Desktop$ sudo docker container exec -it ronie bash
root@b14543669b85:/# ls
bin  boot  dev  etc  home  lib  lib32  lib64  libx32  media  mnt  myfile  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@b14543669b85:/# cat myfile 
test data
root@b14543669b85:/# 

确认之前创建的文件依然存在,并且文件中仍包含之前写入的数据。这说明停止容器运行并不会损毁容器或者其中的数据。

优雅的停止容器

Linux世界中,大部分容器都会运行单一进程;在Windows中可能运行若干个,但是下面的原则对于两者都适用。前面的示例中容器正在运行/bin/bash应用。当使用docker container rm -f来销毁运行中的容器时,不会发出任何告警。这个过程相当暴力——有点像悄悄接近容器后在脑后突施冷枪。毫无征兆地被销毁,会令容器和应用猝不及防,来不及“处理后事”。但是,docker container stop命令就有礼貌多了(就像用枪指着容器的脑袋然后说“你有10s时间说出你的遗言”)。该命令给容器内进程发送将要停止的警告信息,给进程机会来有序处理停止前要做的事情。一旦docker stop命令返回后,就可以使用docker container rm命令删除容器了。这背后的原理可以通过Linux/POSIX信号来解释。docker container stop命令向容器内的PID 1进程发送了SIGTERM这样的信号。就像前文提到的一样,会为进程预留一个清理并优雅停止的机会。如果10s内进程没有终止,那么就会收到SIGKILL信号。这是致命一击。但是,进程起码有10s的时间来“解决”自己。docker container rm -f命令不会先友好地发送SIGTERM,这条命令会直接发出SIGKILL。就像刚刚所打的比方一样,该命令悄悄接近并对容器发起致命一击。顺便说明,我可没有暴力倾向!

重启策略

重启策略应用于每个容器,可以作为参数被强制传入docker-container run命令中,或者在Compose文件中声明,容器支持的重启策略包括always、unless-stopped和on-failed。

  • always策略是一种简单的方式。除非容器被明确停止,比如通过docker container stop命令,否则该策略会一直尝试重启处于停止状态的容器。

    ronie@ronie-virtual-machine:~/Desktop$ sudo docker container run -it --name ronie --restart always ubuntu:latest
    root@171b75aace38:/# ls
    bin  boot  dev  etc  home  lib  lib32  lib64  libx32  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
    root@171b75aace38:/# exit
    exit
    ronie@ronie-virtual-machine:~/Desktop$ sudo docker container ls -a
    CONTAINER ID   IMAGE           COMMAND   CREATED          STATUS         PORTS     NAMES
    171b75aace38   ubuntu:latest   "bash"    18 seconds ago   Up 6 seconds             ronie

    可以注意到容器于18s前被创建,但却在6s前才启动。--restart always策略有一个特性,当daemon重启的时候,停止的容器也会被重启。若新创建一个容器并指定--restart always策略,然后通过docker container stop命令停止该容器。现在容器处于Stopped (Exited)状态。但是,如果重启Docker daemon,该容器也会重新启动。

  • unless-stopped:容器被指定了--restart unless-stopped策略并处于Stopped (Exited)状态的容器,不会在Docker daemon重启的时候被重启。

查看容器详情

使用docker image inspect命令查看容器详情。

ronie@ronie-virtual-machine:~/Desktop$ sudo docker inspect hello-world
[
    {
        "Id": "sha256:feb5d9fea6a5e9606aa995e879d862b825965ba48de054caab5ef356dc6b3412",
        "RepoTags": [
            "hello-world:latest"
        ],
        "RepoDigests": [
            "hello-world@sha256:62af9efd515a25f84961b70f973a798d2eca956b1b2b026d0a4a63a3b0b6a3f2"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2021-09-23T23:47:57.442225064Z",
        "Container": "8746661ca3c2f215da94e6d3f7dfdcafaff5ec0b21c9aff6af3dc379a82fbc72",
        "ContainerConfig": {
            "Hostname": "8746661ca3c2",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ",
                "CMD [\"/hello\"]"
            ],
            "Image": "sha256:b9935d4e8431fb1a7f0989304ec86b3329a99a25f5efdc7f09f3f8c41434ca6d",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {}
        },
        "DockerVersion": "20.10.7",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/hello"
            ],
            "Image": "sha256:b9935d4e8431fb1a7f0989304ec86b3329a99a25f5efdc7f09f3f8c41434ca6d",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 13256,
        "VirtualSize": 13256,
        "GraphDriver": {
            "Data": {
                "MergedDir": "/var/lib/docker/overlay2/21452a4630db39284eb4627ea885b4002231ba2bc3e521189112799daaf2fbc7/merged",
                "UpperDir": "/var/lib/docker/overlay2/21452a4630db39284eb4627ea885b4002231ba2bc3e521189112799daaf2fbc7/diff",
                "WorkDir": "/var/lib/docker/overlay2/21452a4630db39284eb4627ea885b4002231ba2bc3e521189112799daaf2fbc7/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:e07ee1baac5fae6a26f30cabfe54a36d3402f96afda318fe0a96cec4ca393359"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
]

声明:Hello World|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - Docker容器


我的朋友,理论是灰色的,而生活之树是常青的!