Docker容器的创建、启动、停止

容器是独立运行的一个或者一组应用及他们的运行环境。容器是Docker中的一个重要的概念。

Docker容器的两种启动方式

基于镜像新建容器并启动

  1. [root@jk-lx-dev-app01 ~]# docker run centos cal
  2. February 2020
  3. Su Mo Tu We Th Fr Sa
  4. 1
  5. 2 3 4 5 6 7 8
  6. 9 10 11 12 13 14 15
  7. 16 17 18 19 20 21 22
  8. 23 24 25 26 27 28 29

我们还可以通过制定参数,启动一个bash交互终端

  1. [root@jk-lx-dev-app01 ~]# docker run -t -i centos /bin/bash
  2. [root@47efd89bf957 /]# ls
  3. bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
  4. [root@47efd89bf957 /]# exit
  5. exit
  6. [root@jk-lx-dev-app01 ~]#

参数:

-t :让Docker分配一个伪终端并绑定在容器的标准输入上;

-i :让容器的标准输入保持打开状态

使用docker run命令来启动容器,docker在后台运行的标准操作包括

  • 检查本地是否存在指定的镜像,不存在则从公有仓库下载
  • 使用镜像创建并启动容器
  • 分配一个文件系统,并在只读的镜像层外面挂载一层可读可写层
  • 从宿主机配置的网桥接口中桥接一个虚拟接口到容器中
  • 从地址池分批一个IP地址给容器
  • 执行用户指定的应用程序
  • 执行完毕之后容器被终止

启动、关闭

  1. docker start CONTAINER ID
  2. docker stop CONTAINER ID
  3. docker restart CONTAINER ID

守护态运行

很多时候我们希望容器在后台以守护态运行,此时我们可以添加-d参数来实现(d是deamon的首字母)

例如我们启动centos后台容器,每个一秒打印当天的日历

  1. [root@jk-lx-dev-app01 ~]# docker run -d centos /bin/sh -c "while true;do echo hello docker;sleep 1;done"
  2. [root@jk-lx-dev-app01 ~]# docker ps
  3. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  4. 9cfcdd86b046 centos "/bin/sh" 14 seconds ago Up 13 seconds hardcore_grothendieck
  5. [root@jk-lx-dev-app01 ~]# docker logs 9cfcdd86b046
  6. hello docker
  7. hello docker
  8. [root@jk-lx-dev-app01 ~]# docker stop 9cfcdd86b046
  9. 9cfcdd86b046

进入后台运行的容器

后台进入容器

在启动容器的时候,有时候我们加入了参数-d来启动,这是容器自动进入后台运行,这时候我们想进入容器进行操作应该如何操作?通常我们使用docker attach命令或者nsenter工具进行操作。

docker attach

docker run -idt centos /bin/bash

docker ps

docker attach infalible_brown

  1. [root@jk-lx-dev-app01 ~]# docker images
  2. REPOSITORY TAG IMAGE ID CREATED SIZE
  3. centos latest 470671670cac 4 weeks ago 237MB
  4. training/sinatra latest 49d952a36c58 5 years ago 447MB
  5. [root@jk-lx-dev-app01 ~]# docker run -idt centos /bin/bash
  6. 128e13c04ae07b38ac06b0ccc9a4283a9efa7c200b5b39c9876d1455e4db2f61
  7. [root@jk-lx-dev-app01 ~]# docker ps
  8. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  9. 128e13c04ae0 centos "/bin/bash" 36 seconds ago Up 35 seconds xenodochial_shannon
  10. [root@jk-lx-dev-app01 ~]# docker attach 128e13c04ae0
  11. [root@128e13c04ae0 /]# ls
  12. bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var

弊端:docker attach命令是同步的,如果多个用户都在用attach到一个容器,那么一个窗口命令就行阻塞,知道当前用户退出,下一个用户才能进行操作。

nsenter命令

nsenter命令在util-linux包2.23版本之后的包含。nsenter可以访问另一个进行的名字空间

安装

目前Centos7以上版本都随系统安装了util-linux相关系统包,直接使用即可

YUM安装

  1. [root@jk-lx-dev-app01 ~]# yum -y install util-linux-2.32.1-17.el8.x86_64

编译安装

  1. [root@jk-lx-dev-app01 ~]# wget https://www.kernel.org/pub/linux/utils/util-linux/v2.24/util-linux-2.24.tar.gz
  2. [root@jk-lx-dev-app01 ~]# tar -zxvf util-linux-xxx.tar.gz
  3. [root@jk-lx-dev-app01 ~]# cd util-linux-xxx
  4. [root@jk-lx-dev-app01 ~]# ./configure --without-ncurses && make nsenter
  5. [root@jk-lx-dev-app01 ~]# cp nsenter /usr/local/bin

nsenter

为了连接到容器,需要知道容器的pid,可以使用nsenter获取

获取PID

方法1:

  1. [root@jk-lx-dev-app01 ~]# docker container top 2235a7bf01d4
  2. UID PID PPID C STIME TTY TIME CMD
  3. root 5817 5800 0 15:53 pts/0 00:00:00 /bin/bash

方法2:

  1. [root@jk-lx-dev-app01 ~]# docker ps
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. 2235a7bf01d4 centos "/bin/bash" 13 minutes ago Up 13 minutes nifty_einstein
  4. [root@jk-lx-dev-app01 ~]# docker inspect -f '{{.State.Pid}} {{.Id}}' $(docker ps -a -q)
  5. PID CONTAINER ID
  6. 5817 2235a7bf01d4bef8b19790d9f6ed5462935d7ff450347252b7e53c80be0090aa

方法3:

  1. for i in `docker ps |grep Up|awk '{print $1}'`;do echo \ &&docker top $i &&echo ID=$i; done |grep -A 10 <PID>
  1. root@jk-lx-dev-app01 ~]# for i in `docker ps |grep Up|awk '{print $1}'`;do echo \ &&docker top $i &&echo ID=$i; done
  2. UID PID PPID C STIME TTY TIME CMD
  3. root 5817 5800 0 Feb15 pts/0 00:00:00 /bin/bash
  4. ID=2235a7bf01d4

进入指定PID的容器

  1. [root@jk-lx-dev-app01 ~]# nsenter --target 5817 --mount --uts --ipc --net --pid
  2. [root@2235a7bf01d4 /]# ls
  3. bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
  4. [root@2235a7bf01d4 /]# exit
  5. logout
  6. [root@jk-lx-dev-app01 ~]#

查找k8s pod name

  1. docker inspect -f "{{.Id}} {{.State.Pid}} {{.Config.Hostname}}" $(docker ps -q) |grep <PID>

nsenter命令简介

原文链接:https://staight.github.io/2019/09/23/nsenter%E5%91%BD%E4%BB%A4%E7%AE%80%E4%BB%8B/

Man文档链接:http://www.man7.org/linux/man-pages/man1/nsenter.1.html#top_of_page

用途

一个最典型的用途就是进入容器的网络命令空间。相当多的容器为了轻量级,是不包含较为基础的命令的,比如说ip addresspingtelnetsstcpdump等等命令,这就给调试容器网络带来相当大的困扰:只能通过docker inspect ContainerID命令获取到容器IP,以及无法测试和其他网络的连通性。这时就可以使用nsenter命令仅进入该容器的网络命名空间,使用宿主机的命令调试容器网络。

此外,nsenter也可以进入mnt, uts, ipc, pid, user命令空间,以及指定根目录和工作目录。

使用

nsenter命令的语法
  1. nsenter [options] [program [arguments]]
  2. options:
  3. -t, --target pid:指定被进入命名空间的目标进程的pid
  4. -m, --mount[=file]:进入mount命令空间。如果指定了file,则进入file的命令空间
  5. -u, --uts[=file]:进入uts命令空间。如果指定了file,则进入file的命令空间
  6. -i, --ipc[=file]:进入ipc命令空间。如果指定了file,则进入file的命令空间
  7. -n, --net[=file]:进入net命令空间。如果指定了file,则进入file的命令空间
  8. -p, --pid[=file]:进入pid命令空间。如果指定了file,则进入file的命令空间
  9. -U, --user[=file]:进入user命令空间。如果指定了file,则进入file的命令空间
  10. -G, --setgid gid:设置运行程序的gid
  11. -S, --setuid uid:设置运行程序的uid
  12. -r, --root[=directory]:设置根目录
  13. -w, --wd[=directory]:设置工作目录
  14. 如果没有给出program,则默认执行$SHELL

示例

运行一个nginx容器,查看该容器的pid:

  1. [root@staight ~]# docker inspect -f {{.State.Pid}} nginx
  2. 5645

然后,使用nsenter命令进入该容器的网络命令空间:

  1. [root@staight ~]# nsenter -n -t5645
  2. [root@staight ~]# ip addr
  3. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  4. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  5. inet 127.0.0.1/8 scope host lo
  6. valid_lft forever preferred_lft forever
  7. 18: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
  8. link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
  9. inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
  10. valid_lft forever preferred_lft forever

在Kubernetes中,在得到容器pid之前还需获取容器的ID,可以使用如下命令获取:

  1. [root@node1 test]# kubectl get pod test -oyaml|grep containerID
  2. - containerID: docker://cf0873782d587dbca6aa32f49605229da3748600a9926e85b36916141597ec85

或者更为精确地获取containerID:

  1. [root@node1 test]# kubectl get pod test -o template --template='{{range .status.containerStatuses}}{{.containerID}}{{end}}'
  2. docker://cf0873782d587dbca6aa32f49605229da3748600a9926e85b36916141597ec85

导入、导出、删除容器

导出

使用docker export CONTAINER ID 进行导出,导出的为镜像的快照

  1. [root@jk-lx-dev-app01 ~]# docker ps
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. 2235a7bf01d4 centos "/bin/bash" 25 hours ago Up 25 hours nifty_einstein
  4. [root@jk-lx-dev-app01 ~]# docker export 2235a7bf01d4 > ./centos.tar
  5. [root@jk-lx-dev-app01 ~]# ls
  6. centos.tar
  7. [root@jk-lx-dev-app01 ~]#

导入

使用docker import导入

  1. [root@jk-lx-dev-app01 ~]# docker images
  2. REPOSITORY TAG IMAGE ID CREATED SIZE
  3. centos latest 470671670cac 4 weeks ago 237MB
  4. training/sinatra latest 49d952a36c58 5 years ago 447MB
  5. [root@jk-lx-dev-app01 ~]# cat centos.tar | docker import - import/centos:v.2.0.1
  6. sha256:3ebf5bc49a719c608c6a806ecb2c25ff2892d672261a3c53b3c2ef2d8588d763
  7. [root@jk-lx-dev-app01 ~]# docker images
  8. REPOSITORY TAG IMAGE ID CREATED SIZE
  9. import/centos v.2.0.1 3ebf5bc49a71 4 seconds ago 237MB
  10. centos latest 470671670cac 4 weeks ago 237MB
  11. training/sinatra latest 49d952a36c58 5 years ago 447MB
  12. [root@jk-lx-dev-app01 ~]#

导入某个URL的镜像

  1. [root@jk-lx-dev-app01 ~]# docker import http://xxxx.com/image_test.tgz test/images_test

导入方法的区别

docker可以使用docker load来导入镜像,也可以使用docker import来导入一个容器快照到docker镜像。两者的区别在于容器快照将丢弃所有的历史记录和元数据信息,而docker load导入的镜像保存完整的记录,因此要更大一些。

docker import #导入镜像快照,无元数据和完整记录,相对较小

docker load #导入镜像,有元数据和完整记录,相对较大

删除

使用docker rm删除一个处于停止状态的容器

  1. [root@jk-lx-dev-app01 ~]# docker ps -a
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. 39ea01dff236 8b8e4b9c1098 "/bin/sh -c 'yum -qq…" 9 days ago Exited (1) 9 days ago nice_cori
  4. [root@jk-lx-dev-app01 ~]# docker rm 39ea01dff236
  5. 39ea01dff236
  6. [root@jk-lx-dev-app01 ~]#

使用docker rm中的-f参数强制删除处于运行状态的容器

  1. [root@jk-lx-dev-app01 ~]# docker start 47efd89bf957
  2. 47efd89bf957
  3. [root@jk-lx-dev-app01 ~]# docker ps
  4. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  5. 2235a7bf01d4 centos "/bin/bash" 25 hours ago Up 25 hours nifty_einstein
  6. 47efd89bf957 centos "/bin/bash" 3 days ago Up 9 seconds suspicious_johnson
  7. [root@jk-lx-dev-app01 ~]# docker rm 47efd89bf957
  8. Error response from daemon: You cannot remove a running container 47efd89bf9571fa2f19aca7ab12da8bf3a063ce9f9b279046c794ef2e4d71444. Stop the container before attempting removal or force remove
  9. [root@jk-lx-dev-app01 ~]# docker rm -f 47efd89bf957
  10. 47efd89bf957
  11. [root@jk-lx-dev-app01 ~]# docker ps
  12. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  13. 2235a7bf01d4 centos "/bin/bash" 25 hours ago Up 25 hours nifty_einstein
  14. [root@jk-lx-dev-app01 ~]#