操作Docker容器

容器 是Docker的另一个核心概念。简单来说,容器是镜像的一个运行实例。所不同的是,镜像是静态的只读文件,而容器带有运行时需要的可写文件层,同时,容器中的应用进程处于运行状态。

如果认为虚拟机是模拟运行的一整套操作系统(包括内核、应用运行态环境和其他系统环境)和跑在上面的应用。那么Docker容器就是独立运行的一个(或一组)应用,以及它们必需的运行环境。

1. 容器的常见操作

下面是容器的常用操作命令:

create      创建容器
run         运行容器
pause       暂停容器
unpause     取消暂停继续运行容器
stop        发送 SIGTERM 停止容器
kill        发送 SIGKILL 快速停止容器
start       启动容器
restart     重启容器
attach      attach 到容器启动进程的终端
exec        在容器中启动新进程,通常使用 "-it" 参数
logs        显示容器启动进程的控制台输出,用 "-f" 持续打印
rm          从磁盘中删除容器
## 2. 创建容器
1.新建一个停止状态的容器
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker create -it ubuntu:latest
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker ps  -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                    PORTS               NAMES
f13492a1cba7        ubuntu:latest       "/bin/bash"         26 seconds ago      Created                                       infallible_lamarr

2.创建一个交互型容器
docker run -it --name=hu_ubuntu ubuntu /bin/bash


3.创建一个后台型容器,使用-d参数。
sudo docker run --name hu_demo_ubuntu -d ubuntu /bin/bash -c "while true; do echo hello world; sleep 1; done"

3. 查看容器

1.docker ps 命令,可以查看当前运行的容器
[root@hujianli-docker01 centos]# docker ps
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS               NAMES
7fd009ee1f86        ubuntu                "/bin/bash -c 'while…"   11 minutes ago      Up 11 minutes                           hu_demo_ubuntu
e1e8c619585a        quay.io/coreos/etcd   "/usr/local/bin/etcd…"   20 hours ago        Up 20 hours                             etcd


2.Docker列出所有容器,包括运行的和停止的容器
docker ps -a


3.Docker只列出最后创建的容器
docker ps -l

4.使用 -n=x 选项,此时会列出最后创建的x个容器
docker ps -n=2

4. 查看容器日志

[root@hujianli-docker01 centos]# docker logs -f hu_demo_ubuntu
hello world
hello world


# --tail 标志可以精确控制 logs 输出的日志行数。例如,查看最后5行日志
[root@hujianli-docker01 centos]# docker logs -f --tail=5 hu_demo_ubuntu
hello world
hello world
hello world
hello world
hello world
hello world


#可以通过 -t 标志查看日志产生的时刻
[root@hujianli-docker01 centos]# docker logs -f --tail=5 -t hu_demo_ubuntu
2019-07-05T02:48:53.092986363Z hello world
2019-07-05T02:48:54.095842349Z hello world
2019-07-05T02:48:55.098757187Z hello world
2019-07-05T02:48:56.100865840Z hello world
2019-07-05T02:48:57.104798046Z hello world

5. 启动容器

1.通过容器id启动
docker start 3d5e4ad6455f


2.通过容器名称启动
sudo docker start inspect_shell

[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
3d5e4ad6455f        ubuntu:14.04        "/bin/bash"         18 hours ago        Up 3 seconds                            wonderful_wozniak

6. 新建并启动容器

[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker run ubuntu /bin/echo "hello world"
hello world
# 当利用docker run来创建并启动容器时,Docker在后台运行的标准操作包括: ·检查本地是否存在指定的镜像,不存在就从公有仓库下载;


# 启动一个bash终端,允许用户进行交互:
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker run -it ubuntu:14.04 /bin/bash
root@22c6b5a012b0:/#

#,-t选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上,-i则让容器的标准输入保持打开。


守护态运行
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker run -d ubuntu:14.04 /bin/sh -c "while true;do echo hello world;sleep 1;done"
ca08bd323aecdc48e76918dd66d5e37362add12e81d43e185debc65ca4083f7b

#获取容器的输出信息,可以使用docker logs命令
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker logs ca08
hello world
hello world
hello world
hello world
hello world

7. 查看容器进程

[root@hujianli-docker01 centos]# docker top hu_demo_ubuntu
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                23951               23935               0                   02:31               ?                   00:00:00            /bin
/bash -c while true; do echo hello world; sleep 1; doneroot                25679               23951               0                   02:49               ?                   00:00:00            slee
p 1

8. 查看容器信息

# 查看容器的配置信息,(容器名称、环境变量、运行命令、主机配置、数据卷......配置)
docker inspect hu_demo_ubuntu


# --format 格式化标志,可以查看指定部分的信息
#查看容器的运行状态
[root@hujianli-docker01 centos]# docker inspect --format='{{ .State.Running }}' hu_demo_ubuntu
true

#查看状态值
[root@hujianli-docker01 centos]# docker inspect --format='{{ .State.Status }}' hu_demo_ubuntu
running

# 查看容器的IP地址
[root@hujianli-docker01 centos]# docker inspect --format='{{ .NetworkSettings.IPAddress }}' hu_demo_ubuntu
172.17.0.2

#查看容器的镜像类型
[root@hujianli-docker01 centos]# docker inspect --format='{{ .Config.Image }}' hu_demo_ubuntu
ubuntu

9. 终止容器

#首先向容器发送SIGTERM信号,等待一段超时时间(默认为10秒)后,再发送SIGKILL信号来终止容器:
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
ca08bd323aec        ubuntu:14.04        "/bin/sh -c 'while..."   2 minutes ago       Up 2 minutes                            festive_nobel
3d5e4ad6455f        ubuntu:14.04        "/bin/bash"              18 hours ago        Up 7 minutes                            wonderful_wozniak
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker stop ca08
ca08
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
3d5e4ad6455f        ubuntu:14.04        "/bin/bash"         18 hours ago        Up 7 minutes                            wonderful_wozniak


# docker kill命令会直接发送SIGKILL信号来强行终止容器。
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker kill 3d5e
3d5e
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES



#可以用docker ps-qa命令看到所有容器的ID
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker ps -qa
22c6b5a012b0
bdbdb0d56db9
9339393ce470
f13492a1cba7
3d5e4ad6455f


#可以使用docker start命令来重新启动
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker start 2c53


# docker restart命令会将一个运行态的容器先终止,然后再重新启动它:
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker restart 22c6b5a012b0
22c6b5a012b0

10. 进入容器

1.
# 用attach命令有时候并不方便。当多个窗口同时用attach命令连到同一个容器的时候,所有窗口都会同步显示。当某个窗口因命令阻塞时,其他窗口也无法执行操作了
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
22c6b5a012b0        ubuntu:14.04        "/bin/bash"         10 minutes ago      Up 57 seconds                           dazzling_dijkstra

[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker attach 22c6
root@22c6b5a012b0:/#





2.
# Docker从1.3.0版本起提供了一个更加方便的exec命令,可以在容器内直接执行任意命令。

#进入到刚创建的容器中,并启动一个bash:
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker exec -it 22c6b5a012b0 /bin/bash
root@22c6b5a012b0:/#

# 执行以下命令,启动一个busybox镜像容器
docker run -itd busybox /bin/bash   #下载镜像
docker exec -it b47 /bin/bash       # 进入镜像容器

busybox:是一个mini版本的linux,有linux的所有命令行工具

3.nsenter工具(不常用)
cd /tmp; curl https://www.kernel.org/pub/linux/utils/util-linux/v2.24/util-linux-2.24.tar.gz | tar -zxf -; cd util-linux-2.24;
./configure --without-ncurses
make nsenter && cp nsenter /usr/local/bin

# 使用nsenter连接到容器,先找到容器进程的PID,通过下面的命令获取
[root@iZ2ze38chylj63vuj6fqiaZ util-linux-2.24]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
22c6b5a012b0        ubuntu:14.04        "/bin/bash"         31 minutes ago      Up 18 minutes                           dazzling_dijkstra

[root@iZ2ze38chylj63vuj6fqiaZ util-linux-2.24]# docker inspect -f {{.State.Pid}} 22c6b5a012b0
6450


# PID=$(docker inspect --format "{{ .State.Pid }}" <container>)

[root@iZ2ze38chylj63vuj6fqiaZ util-linux-2.24]# nsenter --target 6450 --mount --uts --ipc --net --pid
root@22c6b5a012b0:/#


#如果只是为了查看启动命令的输出,可以使用 docker logs 命令:



attach VS exec

attach 与 exec 主要区别如下:
attach 直接进入容器 启动命令 的终端,不会启动新的进程。
exec 则是在容器中打开新的终端,并且可以启动新的进程。
如果想直接在终端中查看启动命令的输出,用 attach;其他情况使用 exec。

退出容器,保持容器继续运行:

ctrl-p和ctrl-q。 如果使用exit。退出容器时,容器会自动关闭。

#运行远程机器上的容器
docker run -it -h test.up.com daocloud.io/centos:7

11. 容器内执行命令

# 交互型任务的例子
[root@hujianli-docker01 centos]# docker exec -it 7fd009ee1f86 ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0  18364  1584 ?        Ss   02:31   0:01 /bin/bash -c wh
root      1617  0.0  0.0   4520   384 ?        S    02:58   0:00 sleep 1
root      1618  0.0  0.0  34388  1472 pts/0    Rs+  02:58   0:00 ps aux

# 后台型任务的例子:
$ sudo docker exec -d daemon_dave touch /etc/new_config_file

12. (暂停/恢复)容器

[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
350a409c2eb2        nginx               "nginx -g 'daemon ..."   4 seconds ago       Up 3 seconds        0.0.0.0:8080->80/tcp   epic_meninsk

#暂停工作,比如对文件系统打快照

[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker pause 350a4
350a4
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                   PORTS                  NAMES
350a409c2eb2        nginx               "nginx -g 'daemon ..."   26 seconds ago      Up 25 seconds(Paused)    0.0.0.0:8080->80/tcp   epic_menins


# 恢复容器运行
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker unpause 350a4
350a4
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
350a409c2eb2        nginx               "nginx -g 'daemon ..."   2 minutes ago       Up About a minute   0.0.0.0:8080->80/tcp   epic_menins

13. 删除容器

#默认情况下,docker rm命令只能删除处于终止或退出状态的容器,并不能删除还处于运行状态的容器
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                        PORTS               NAMES
22c6b5a012b0        ubuntu:14.04        "/bin/bash"              35 minutes ago      Up 22 minutes                                     dazzling_dijkstra
bdbdb0d56db9        ubuntu              "/bin/echo 'hello ..."   36 minutes ago      Exited (0) 36 minutes ago                         eloquent_swartz
9339393ce470        ubuntu              "/bin/bash echo 'h..."   36 minutes ago      Exited (126) 36 minutes ago                       objective_blackwell
f13492a1cba7        ubuntu:latest       "/bin/bash"              40 minutes ago      Created                                           infallible_lamarr
3d5e4ad6455f        ubuntu:14.04        "/bin/bash"              19 hours ago        Exited (137) 29 minutes ago                       wonderful_wozniak

[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker rm 3d5e4ad6455f
3d5e4ad6455f

# 如果要直接删除一个运行中的容器,可以添加-f参数
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker run -d ubuntu:14.04 /bin/sh -c "while true;do echo hello world;sleep 1;done"
d8f004f4573f9703d3734d3f0096ff5ba209f0b16e9c7b5d6b528b166acd9b66


[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker rm d8f00
Error response from daemon: You cannot remove a running container d8f004f4573f9703d3734d3f0096ff5ba209f0b16e9c7b5d6b528b166acd9b66. Stop the container before attempting removal

or use -f[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker rm -f  d8f00
d8f00


# 同时删除后台多个容器
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker rm $(docker ps -qa)
bdbdb0d56db9
9339393ce470

或者:
#docker rm 一次可以指定多个容器,如果希望批量删除所有已经退出的容器,可以执行如下命令:

## 根据格式删除所有容器,容器的状态为停止的
docker rm -v $(docker ps -aq -f status=exited)
docker rm $(docker ps -a -q)

## 强制批量删除
docker rm $(docker ps -a -q) --force

# 使用awk实现
docker rm $(docker ps -a|awk '/Exited/{print $1}')

#或者批量清理临时镜像文件
docker rmi $(docker images -q -f dangling=true)

#批量删除运行中的容器
docker rm -f $(docker ps|grep -v "CONTAINER"|awk '{print $1}')

# 执行无法删除运行中的容器,我们需要先停止然后在删除
docker stop d8f00
docker rm d8f00

14. 其他容器操作

14.1 复制文件

# 容器数据向外复制
Usage:  docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-

# 外部数据复制到容器内
        docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH
$ docker cp 9eac3a /var/jenkins_home/gitee_workspace_parallel/ /home/
"docker cp" requires exactly 2 arguments.
See 'docker cp --help'.

14.2 查看变更

查看jenkins_jenkins_1容器内的数据修改:

$ docker container diff jenkins_jenkins_1
C /tmp
A /tmp/hsperfdata_jenkins
A /tmp/hsperfdata_jenkins/6
A /tmp/jetty-0_0_0_0-8080-war-_-any-6407271552317565788.dir
A /tmp/jetty-0_0_0_0-8080-war-_-any-6753302642276023631.dir
A /tmp/jetty-0_0_0_0-8080-war-_-any-6829047221675530177.dir
A /tmp/winstone3743544242970475678.jar
A /tmp/winstone4225465649559590246.jar
A /tmp/winstone7204593242092902219.jar

14.3 查看端口映射

$ docker container port jenkins_jenkins_1
8080/tcp -> 0.0.0.0:8080

15.导入和导出容器

15.1 导出容器

[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                        PORTS               NAMES
22c6b5a012b0        ubuntu:14.04        "/bin/bash"              40 minutes ago      Up 26 minutes                                     dazzling_dijkstra
bdbdb0d56db9        ubuntu              "/bin/echo 'hello ..."   41 minutes ago      Exited (0) 41 minutes ago                         eloquent_swartz
9339393ce470        ubuntu              "/bin/bash echo 'h..."   41 minutes ago      Exited (126) 41 minutes ago                       objective_blackwell
f13492a1cba7        ubuntu:latest       "/bin/bash"              45 minutes ago      Created                                           infallible_lamarr

#分别导出容器f13492a1cba7和容器22c6b5a012b0 到文件test_for_ubuntu:latest和文件test_for_run_ubuntu.tar
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker export -o test_for_ubuntu:latest f13492
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker export 22c6b > test_for_run_ubuntu.tar
之后,可将导出的tar文件传输到其他机器上,然后再通过导入命令导入到系统中,从而实现容器的迁移。

15.2 导入容器

[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                        PORTS               NAMES
bdbdb0d56db9        ubuntu              "/bin/echo 'hello ..."   48 minutes ago      Exited (0) 48 minutes ago                         eloquent_swartz
9339393ce470        ubuntu              "/bin/bash echo 'h..."   49 minutes ago      Exited (126) 49 minutes ago                       objective_blackwell

[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker import test_for_ubuntu\:latest  test_hu/ubuntu:14.04
sha256:d8a336bc07fd1b05266710a5d93f05d6a08dae99d0ae5afa1498ad9a78325191
[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker import test_for_run_ubuntu.tar run_hu/ubuntu:14.04
sha256:a7c21f91b4afe37b48a1abc1b15ce2cd7b5c759367579b0837a4c6f64332a65f

[root@iZ2ze38chylj63vuj6fqiaZ ~]# docker images
REPOSITORY                         TAG                 IMAGE ID            CREATED             SIZE
run_hu/ubuntu                      14.04               a7c21f91b4af        4 seconds ago       175 MB
test_hu/ubuntu                     14.04               d8a336bc07fd        11 seconds ago      69.9 MB

16. docker资源限制

-m --memory      #限制容器使用的内存
--memory-swap    #允许交换分区到磁盘的内存
--memory-swappiness=<0-100>  #容器使用swap的百分比,默认关闭-1
--oom-kill-disable   #禁用oom
--cpus           #可以使用cpu的数量[常用]
--cpuset-cpus    #限制容器使用特定的cpu 如: 0-3 0,1
--cpu-shares     #cpu共享(相对的权重)

资源限制示例:

#限制内存500MB 开启swap600MB 禁止被oom
$ docker run -d --name nginx01 --memory="500m" --memory-swap="600m" --oom-kill-disable nginx

#限制CPU示例,最多可以使用1.5个cpu
$ docker run -d --name nginx02 --cpus="1.5" nginx

#限制最多使用50%cpu
$ docker run -d --name nginx05 --cpus=".5" nginx
#内存
$ docker run -m 200M --memory-swap=300M ubuntu
#其含义是允许该容器最多使用 200M 的内存和 100M 的 swap。默认情况下,上面两组参数为 -1,即对容器内存和 swap 的使用没有限制

$ docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 280M
# --vm 1:启动 1 个内存工作线程。
# --vm-bytes 280M:每个线程分配 280M 内存。

#####如果在启动容器时只指定 -m 而不指定 --memory-swap,那么 --memory-swap 默认为 -m 的两倍,比如:
$ docker run -it -m 200M ubuntu
容器最多使用 200M 物理内存和 200M swap。

#CPU
# 比如在 host 中启动了两个容器:
$ docker run --name "container_A" -c 1024 ubuntu
$ docker run --name "container_B" -c 512 ubuntu
#container_A 的 cpu share 1024,是 container_B 的两倍。当两个容器都需要 CPU 资源时,container_A 可以得到的 CPU 是 container_B 的两倍

# Block IO
$ docker run -it --name container_A --blkio-weight 600 ubuntu
$ docker run -it --name container_B --blkio-weight 300 ubuntu

# 限制 bps 和 iops
#bps 是 byte per second,每秒读写的数据量。
#iops 是 io per second,每秒 IO 的次数。

可通过以下参数控制容器的 bps 和 iops:
--device-read-bps,限制读某个设备的 bps。
--device-write-bps,限制写某个设备的 bps。
--device-read-iops,限制读某个设备的 iops。
--device-write-iops,限制写某个设备的 iops。

17. 容器和镜像转化、迁移方式

一、容器转化为镜像(docker export、docker import)
1)docker export:表示将容器导出文件包
两种命令方式(finhub-cms为容器名):
docker export finhub-cms > finhub-cms.tar
docker export -o finhub-cms.tar finhub-cms

2)docker import:表示根据docker export 导出的文件包新建一个镜像。可以基于这个新镜像创建容器,实现容器迁移。
另种命令方式:
docker import finhub-cms.tar finhub-cms:v1
cat finhub-cms.tar | docker import - finhub-cms:v1

3)docker commit:也可以实现将容器转化为镜像。
docker commit finhub-cms finhub-cms:v1



二、镜像迁移(镜像导出、镜像导入)
1)docker save:表示将镜像打包,方便迁移
两种命令方式(finhub-cms:v1为镜像名):
docker save finhub-cms:v1 > finhub-cms_v1.tar.gz
docer save -o finhub-cms_v1.tar.gz finhub-cms:v1

2)docker load: 表示将docker save导出的镜像包导入到本地仓库
两种命令方式:
docker load < finhub-cms_v1.tar.gz
docker load --input finhub-cms_v1.tar.gz



三、注意细节
一般情况下:
docker save 导出的镜像包 要比docker export打成的容器文件包大一点。
这是因为docker export导出的容器包 丢失了历史和元数据metadata。

参考文献: https://www.cnblogs.com/kevingrace/p/14434806.html

18.使用Kitematic来管理Docker容器

Kitematic是一个开源项目,旨在简化在Mac或Windows PC上使用Docker的过程。Kitematic自动化Docker安装和设置过程,并提供直观的图形用户界面(GUI)来运行Docker容器。

因此,我们推荐使用Kitematic工具来查看和管理自己的容器服务。如果尚未安装此工具,可以通过以下方式进行安装:

● 从Docker for Mac或Docker for Windows菜单中选择“Kitematic”选项,开始使用Kitematic安装。

● 直接从Kitematic版本页面下载Kitematic,下载地址为https://github.com/docker/kitematic/releases/。

另外,Kitematic集成了Docker Hub,允许通过搜索、拉取任何需要的镜像,并在上面部署应用,同时也能很好地切换到命令行模式。目前包括自动映射端口、可视化更改环境变量、配置卷、流式日志等功能。

如果安装完成后无法打开,可以将Kitematic安装后的文件迁移到Docker指定目录“C:\Program Files\Docker\Kitematic”。

Kitematic是开源的,如果大家有兴趣,可以访问其开源库下载全部源代码进行研究,下载地址为https://github.com/docker/kitematic。