容器

容器简介

容器就是镜像的运行时示例。正如从虚拟机模板启动 VM 一样,用户也同样可以从单个镜像上启动一个或多个容器。就像使用一个 OS 镜像在 VMware 装多个系统一样。

使用单个Docker镜像启动多个容器

虚拟机与容器

  • 虚拟机和容器最大的区别是容器更快更加便捷轻量
  • 虚拟机是在操作系统上新建的一个操作系统,不与操作系统共享内核,有自己的操作系统和内核
  • 容器是在操作系统上新建的容器,与操作系统共享内核

启动容器方法 docker container run 命令启动容器,该命令可以携带许多参数。

基础格式 docker container run <image> <app> 中,指定了启动所需的镜像以及要运行的应用。

docker container run -it ubuntu /bin/bash 启动某个 Ubuntu Linux 容器,运行 /bin/bash 作为应用进行启动

-it 参数可以将当前终端连接到容器的 shell 终端之上

容器随着启动运行应用程序的退出而终止。linux 容器会在 /bin/bash 退出后终止。简单的验证方法 docker container run -it [image] sleep 10 这条命令可以验证容器是根据运行在自己身上的应用来决定自己是否正在运行的。

docker container stop 停止容器正在运行的应用

docker container rm 删除容器正在运行的应用

容器和虚拟机

虚拟机与容器都是寄居在物理机上运行的。

虚拟机

运行4个业务应用的物理服务器

虚拟机是将物理机的物理资源通过 Hypervisor 划分成多个 VM 小块并封装,在这个封装的 VM 环境中,安装自己单独的 OS 系统,并且可以在系统上安装相应的应用。一旦 Hypervisor 启动,那么就会占用所有的主机资源。虚拟机是将硬件的物理资源划分,在物理资源上直接创建的虚拟机系统,且整个架构可以装载自定义的操作系统

容器

划分4个容器

容器是在操作系统之上运行了多个容器,这个容器是通过 docker daemon 创建并管理的,在操作系统还必须要安装容器引擎来运行单个容器,并且操作系统与 dockcer daemon 之间会共享内核资源。容器是在当前操作系统中运行的,且整个架构只需要运行一台操作系统即可。

因为操作系统也会占用一些资源,所以容器相对来说更加的轻量化。

容器的管理命令

查看 docker 是否正在运行

如果查询出的 version 的 server 字段出现错误码,那么就说明你的用户没有权限或者是 docker 没有启动。

如果是用户没有权限,那么可以使用 usermod -aG 将用户添加到 docker 组中

正常内容

[root@centos7 docker]# docker version
Client: Docker Engine - Community
 Version:           19.03.13
 API version:       1.40
 Go version:        go1.13.15
 Git commit:        4484c46d9d
 Built:             Wed Sep 16 17:03:45 2020
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.13
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.13.15
  Git commit:       4484c46d9d
  Built:            Wed Sep 16 17:02:21 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.3.7
  GitCommit:        8fba4e9a7d01810a393d5d25a3621dc101981175
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

无权限报错

[chen@centos7 docker]$ docker version
Client: Docker Engine - Community
 Version:           19.03.13
 API version:       1.40
 Go version:        go1.13.15
 Git commit:        4484c46d9d
 Built:             Wed Sep 16 17:03:45 2020
 OS/Arch:           linux/amd64
 Experimental:      false
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.40/version: dial unix /var/run/docker.sock: connect: permission denied

其他方法

[root@centos7 docker]# service docker status
[root@centos7 docker]# systemctl is-active docker
active

启动一个简单容器

启动容器的一个简单方式是通过 docker container run 命令。

基础格式

docker container run <options> <im- age>:<tag> <app>

使用该命令指定了一个镜像后,docker 客户端会选择合适的 API 来调用 Docker daemon。

Docker daemon 接收到命令并搜索 Docker 本地缓存,观察是否有命令所请求的镜像。Docker daemon 接收到命令并搜索 Docker 本地缓存,观察是否有命令所请求的镜像。

如果本地缓存并未包含该镜像,所以 Docker 接下来查询在Docker Hub 是否存在对应镜像。找到该镜像后,Docker 将镜像拉取到本地,存储在本地缓存中。

通过配置,也可以借助网络实现 Docker Client 和 daemon 之间的通信。

Docker 默认非 TLS 网络端口为 2375,TLS 默认端口为 2376。

一旦将镜像拉取到本地,daemon 就会创建并在其中运行指定的应用。

如果发现 shell 提示符发生了变化,那么就是进入到了容器内部。显示命令提示符的一串数字就是容器唯一 ID 的前 12 个字符。

如果尝试在容器内执行一些基础命令,可能会发现某些指令无法正常工作,因为这些容器都是经过高度优化(精简,裁剪)过的,有些命令所依赖的安装包可能并没有安装。

root@464b52f2d98e:/# ls
bin  boot  dev  etc  home  lib  lib32  lib64  libx32  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@464b52f2d98e:/# ss
bash: ss: command not found
root@464b52f2d98e:/# ip
bash: ip: command not found
root@464b52f2d98e:/# ping
bash: ping: command not found

容器进程

通过镜像启动容器后,使用 ps -elf 命令查看,发现会存在两个进程,其中一个是 bash 进程,是 linux 开启容器时打开的第一个进程。另一个是 ps -elf 进程,这个是个临时进程,当这条命令执行完成后进程在后台也就消失了。

root@d233601c08e7:/# ps -elf
F S UID         PID   PPID  C PRI  NI ADDR SZ WCHAN  STIME TTY          TIME CMD
4 S root          1      0  0  80   0 -  1025 do_wai 07:29 pts/0    00:00:00 /bin/bash
0 R root          8      1  0  80   0 -  1470 -      07:30 pts/0    00:00:00 ps -elf

为什么容器运行时必须需要一个进程?

这是因为容器如果不运行一个进程则无法存在。如果将该进程杀死,那么该容器将会被终结。

使用 exit 可以终止容器的运行,因为只存在一个进程

root@8cef18d05815:/# exit
exit
[root@centos7 docker]# docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

可以使用 Ctrl + PQ 暂时将容器保留在后台,然后可以使用 docker container exec 重新连接到容器中

[root@centos7 docker]# docker container run -it ubuntu
root@f095a3c7dc71:/# [root@centos7 docker]#

[root@centos7 docker]# docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
f095a3c7dc71        ubuntu              "/bin/bash"         23 seconds ago      Up 22 seconds                           objective_mclaren

重新进入到容器中
[root@centos7 docker]# docker container exec -it f095a3c7dc71 /bin/bash
root@f095a3c7dc71:/#

查看进程,因为刚才也是执行 bash 命令后进入的,所以后台现在有两个 bash 环境,所以即使 exit 退出,也不会终止容器
root@f095a3c7dc71:/# ps -elf
F S UID         PID   PPID  C PRI  NI ADDR SZ WCHAN  STIME TTY          TIME CMD
4 S root          1      0  0  80   0 -  1025 poll_s 07:35 pts/0    00:00:00 /bin/bash
4 S root          8      0  0  80   0 -  1025 do_wai 07:38 pts/1    00:00:00 /bin/bash
0 R root         16      8  0  80   0 -  1470 -      07:39 pts/1    00:00:00 ps -elf

root@f095a3c7dc71:/# exit
exit
[root@centos7 docker]# docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
f095a3c7dc71        ubuntu              "/bin/bash"         4 minutes ago       Up 4 minutes                            objective_mclaren

关闭并杀死容器

docker container stop [ID] 停止正在运行的容器,docker container rm [ID] 删除已经停止的容器,如果不先停止那么会出现错误。

$ docker container stop 3027eb64487
3027eb64487

$ docker container rm 3027eb64487
3027eb64487

容器生命周期

容器可能是因为在非持久化领域上表现得太过出色,导致人们认为容器不擅长持久化工作,或者是持久化数据。

为容器起名为 percy 并使用 docker container 命令启动容器

[root@centos7 docker]# docker container run --name procy  -it ubuntu /bin/bash
root@35d03eafda20:/#

进入容器的某个地方,写入一些数据,并且要确认数据是否写入成功

root@35d03eafda20:/# cd tmp/
root@35d03eafda20:/tmp# echo "test,this is percy container" > 1.txt
root@35d03eafda20:/tmp# cat 1.txt
test,this is percy container

Ctrl + PQ 将容器转移到后台运行

root@35d03eafda20:/tmp# [root@centos7 docker]#

停止该容器的运行并重新开启,再次查看文件内容

[root@centos7 docker]# docker container stop 35d03eafda20
[root@centos7 docker]# docker container exec -it procy /bin/bash
root@35d03eafda20:/# cat /tmp/1.txt
test,this is percy container

停止并删除该容器重启开启再次查看文件内容,发现数据已经丢失

[root@centos7 docker]# docker container stop 35d03eafda20
35d03eafda20
[root@centos7 docker]# docker container rm 35d03eafda20
35d03eafda20
[root@centos7 docker]# docker container run --name procy -it ubuntu /bin/bash
root@c314e0c924f5:/# ls /tmp/

得出的结论就是,容器只要没有使用 rm 删除运行的容器,只要在后台就可以恢复到前台,并且容器也会一直保留数据。但是删除后容器内的数据就会丢失。并且在启动关闭或者是重启容器时这些操作都可以执行的很快,就算容器被删除了,如果将容器的数据保存在卷中,那么数据也会保留下来。

优雅的停止容器

如果直接使用 docker container rm -f 命令删除正在运行的容器,无异于背后放冷枪,系统会直接发送 SIGKILL 强制杀死容器。

正确的关闭方式应该是先使用 docker container stop 然后使用 docker container rm 删除进程,docker container stop 就是很委婉的告诉容器,你要关闭,然后容器开始自己料理自己的后事,准备死亡。当十秒过后,系统发来 SIGKILL 信号,容器宣布死亡。

利用重启策略进行容器的自我修复

容器的重启策略包括 always、unless-stopped 和 on-failed,指定策略格式 --restart [模式],重启策略是在非指定关闭时会生效。如果使用 docker container stop 方式关闭,是不会触发重启策略。

always 方式介绍

  • 重启 daemon 后以 always 方式运行的容器也会运行
案例

以 always 方式运行容器,关闭容器,查看是否还在运行

[root@centos7 docker]# docker container run --restart always -it ubuntu  /bin/bash
root@75d1404942e4:/# exit
exit
[root@centos7 docker]# docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                  PORTS               NAMES
75d1404942e4        ubuntu              "/bin/bash"         2 seconds ago       Up Less than a second                       gifted_bassi
[root@centos7 docker]# docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
75d1404942e4        ubuntu              "/bin/bash"         3 seconds ago       Up 1 second                             gifted_bassi


关闭容器,重启 docker ,发现之前使用 always 方式启动的容器又启动了
[root@centos7 docker]# docker container stop 75d1404942e4
75d1404942e4
[root@centos7 docker]# systemctl stop docker
[root@centos7 docker]# systemctl start docker
[root@centos7 docker]# docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
75d1404942e4        ubuntu              "/bin/bash"         5 minutes ago       Up 4 seconds                            gifted_bassi

unless-stopped 方式介绍

  • 直接使用 exit 退出容器会重启
  • 这种方式原本停止容器后重启 docker 容器也不会启动
[root@centos7 docker]# docker container run --restart unless-stopped --name test -it ubuntu /bin/bash
root@14b1602ea009:/# exit
exit
[root@centos7 docker]# docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
14b1602ea009        ubuntu              "/bin/bash"         6 seconds ago       Up 3 seconds                            test

没有关闭重启
[root@centos7 docker]# systemctl restart docker
[root@centos7 docker]# docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
14b1602ea009        ubuntu              "/bin/bash"         About a minute ago   Up 1 second                             test

on-failure 方式介绍

  • 就算容器处于 stopped 状态,在 Docker daemon 重启的时候,容器也会被重启
[root@centos7 docker]# docker container stop test2
test2
[root@centos7 docker]# systemctl restart docker
[root@centos7 docker]# docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
a8ba07eb4c59        ubuntu              "/bin/bash"         About a minute ago   Up About a minute                       test2

web 服务器示例

在 Docker hub 拉取一个 nginx 的镜像,使用 docker container run 命令启动该容器并将端口映射。

[root@centos7 docker]# docker container run -d --name web -p 80:80 nginx
-d 指定为后台运行进程
--name 指定运行容器的名称
-p 指定将容器内部的 80 端口映射到宿主机的 80 端口
最后启动 nginx

可以使用 docker

快速清理

[root@centos7 docker]# docker container rm -f `docker container ls -qa`

管理命令

docker container ls 查看正在运行的容器,如果加上 -a 那么出现的也会有 exits 状态

docker container inspect 查看容器的详细信息

docker container rm 删除已经停止的容器,加上 -f 那么将会强制删除

docker container start 启动容器

docker container stop 停止容器

docker container restart 重启容器

docker container exec 进入一个在后台运行的容器