Docker容器相对于OpenStack的云主机实例,虽然他们本质上不同。我们需要基于镜像来创建容器。容器是独立运行的一个或一组应用,以及它们的运行环境。对应的,虚拟机可以理解为模拟运行的一整套操作系统和跑在上面的应用。

启动容器

启动容器其实就是创建镜像并启动,启动镜像有两种方式,一种是将已经存在,但是是stopped状态的镜像启动,一种就是基于一个镜像新建一个新的容器并启动。

新建并启动容器

让我们先老生常谈,输出一个Hello World吧。

[root@linux-node1 ~]# docker run centos /bin/echo 'Hello world'

Hello world

很神奇,可以在精通各种语言的Hello World计数器+1了,这个和你在本地系统运行/bin/echo ‘Hello world’ 几乎没有任何区别,但是它是Docker容器输出的,而且输出后,它就完成使命,自动退出了。

注意:这里就是我们学习Docker要面临的第一个疑惑,就是容器只会在前台运行一个任务,任务结束,容器就终止了。

使用docker ps –a可以查看当前启动的容器:

[root@linux-node1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
789de67bb454 centos "/bin/echo 'Hello wor" 30 seconds ago Exited (0) 29 seconds
ago pedantic_kare

刚接触Docker到这里还会有第二个疑惑:

Docker自动帮你生成了一个名字,比如本例中是pedantic_kare。

很困惑?好吧,让我们来启动一个我们自定义名称,同时可以有终端的容器,就像启动一个虚拟机一样,不过只是像而已,它们本质上完全不同。

[root@linux-node1 ~]# docker run --name mydocker -t -i centos /bin/bash
[root@1b0cae722fa0 /]#
[root@1b0cae722fa0 /]# ls / anaconda-post.log bin dev etc home lib lib64 lost+found media mnt opt proc root
run sbin srv sys tmp usr var

上面我们使用了两个选项,-t 选项让Docker分配一个伪终端并绑定到容器的标准输入上, -i 则让容器的标准输入保持打开。

在交互模式下,用户可以通过所创建的终端来输入命令,例如我们可以查看当前运行的进程,只有/bin/bash和你运行的命令,注意看/bin/bash的PID为1,有意思。先记着这个特殊的地方,随着我们深入学习,再回过头来研究它。

[root@1b0cae722fa0 /]# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.1 0.1 11776 1872 ? Ss 15:30 0:00 /bin/bash
root 18 0.0 0.0 47424 1660 ? R+ 15:31 0:00 ps aux

当利用 docker run 来创建容器时,Docker 在后台运行的标准操作包括:

  • 检查本地是否存在指定的镜像,不存在就从公共仓库下载;

  • 利用镜像创建并启动一个容器;

  • 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层;

  • 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去;

  • 从地址池配置一个ip地址给容器;

  • 执行用户指定的应用程序;

  • 执行完毕后容器被终止。

让我们输入exit来退出这个容器,退出后,容器会自动终止运行。为什么呢?请参考我们第一个疑惑,Docker容器在前台运行一个单任务,任务结束,容器就终止。这就是Docker容器的特性!同时你有没有注意到一个小细节,默认docker容器的主机名就是CONTAINER ID。

让容器容器后台运行

在使用docker run运行容器更多时候,我们是需要容器在后台运行的,也就是以守护态形式运行。可以通过-d参数来实现。

[root@linux-node1 ~]# docker run -d --name mydocker2 centos /bin/bash
38e42accfa2226bb6c7da2e28e12dc95f6b6d6717326442131887a24bb321cdd

容器启动后就会在后台运行,然后返回一个容器ID到控制台,而且上面这个容器也终止了,带着问题继续前进。

终止容器

在前面的输出Hello World的操作中我们看到了,当Docker容器中指定的应用程序运行完毕,容器也就自动终止了。同时我们可以使用exit命令退出运行/bin/bash的终端,同时我们也可以使用Ctrl+d来实现同样的效果。

使用docker stop来停止一个容器,默认是先给容器发送SIGTERM信号,然后10秒后发生SIGKILL信号终止容器,可以使用-t或者—time来设置等待的时间,单位是秒

docker stop 容器名称、容器ID

对于终止的容器,可以使用docker start来启动,或者使用docker restart来重启。

[root@bc419cd0b8fa /]# exit
Exit

可以使用docker ps –a来查看容器的状态,发现已经是停止模式。

[root@linux-node1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
38e42accfa22 centos "/bin/bash" 17 seconds ago Exited (0) 16 seconds ago
mydocker2
a5ef57e8783f centos "/bin/bash" 3 minutes ago Exited (0) About a minute ago
mydocker
d132d6e645ad centos "/bin/echo 'Hello wo…" 3 minutes ago Exited (0) 3 minutes
ago serene_dijkstra

启动已终止容器

可以使用docker start来开启已经终止的容器,可以通过输入容器的CONTAINER ID,或者NAMES来进行启动。

[root@linux-node1 ~]# docker start mydocker
mydocker

好的,我们又一次启动了运行/bin/bash的容器,那么问题来了,我们怎么进去呢。

进入容器

Docker attach

Docker提供了docker attach的命令,用来让我们进入已经启动的容器(如果容器已经终止,你需要使用docker start将它启动。

[root@linux-node1 ~]# docker attach mydocker
[root@a5ef57e8783f /]#

你可以继续执行一些命令,没错,很多命令都没有。

注意,在我们使用 attach 进入容器的时候,如果同时有多个窗口 attach 到同一个容器的时候,所有窗口都会同步显示。当某个窗口因命令阻塞时,其他窗口也无法执行操作了。这可怎么办,如果我们是团队作战,可能多个同事需要同时进入容器操作呢?还有一个最关键的问题。你输入exit以后呢?之前运行的容器退出了。

nsenter进入容器

nsenter命令被包含在util-linux软件包里面,使用nsenter可以访问另一个进程的名字空间,大多数Linux发行版默认包含了该软件,CentOS默认是有的。如果你的系统里面没有可以使用以下命令进行安装:

Yum安装:

[root@docker ~]# yum install -y util-linux

为了连接到容器,你还需要找到容器的第一个进程的 PID,可以通过下面的命令获取。

# docker inspect --format "{{ .State.Pid }}" <container ID or NAMES>

通过这个 PID,就可以连接到这个容器:

# nsenter --target $PID --mount --uts --ipc --net –pid

如果你刚才停止了容器,请启动。

连接方式如下:

[root@linux-node1 ~]# PID=$(docker inspect --format "{{ .State.Pid }}"
mydocker)
[root@linux-node1 ~]# echo $PID
8029

注意如果你的PID变量为0,说明mydocker容器没有启动。

[root@linux-node1 ~]# nsenter --target $PID --mount --uts --ipc --net --pid
[root@a5ef57e8783f /]# ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 21:11 pts/0 00:00:00 /bin/bash root 14 0 0 21:12 pts/0 00:00:00 -bash root 27 14 0 21:12 pts/0 00:00:00 ps -ef

编写一个脚本用户进入容器

[root@linux-node1 ~]# vim docker_in.sh
#!/bin/bash
# Use nsenter to access docker
docker_in(){
NAME_ID=$1
PID=$(docker inspect --format "{{ .State.Pid }}" $NAME_ID)
nsenter --target $PID --mount --uts --ipc --net --pid
}
docker_in $1
[root@linux-node1 ~]# chmod +x docker_in.sh

这么后面的内容,我们就直接使用docker_in.sh这个脚本来进入Docker容器,只要传给它名称或者容器ID即可,就像下面这样:

[root@linux-node1 ~]# ./docker_in.sh mydocker

不进入容器执行命令

或许你的本意不是想进去容器,而是想让容器执行一个命令,docker提供了exec,使用exec可以在容器内运行命令。

[root@linux-node1 ~]# docker exec mydocker whoami
root

使用exec进入容器

[root@linux-node1 ~]# docker exec -it mydocker /bin/bash

注意,现在你进入容器和其它方法都是不一样的,其实是你执行了一个/bin/bash的命令,所以你现在拥有了一个shell,你现在所在的shell应该是下图中PID为33的进程。

[root@1b0cae722fa0 /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 15:37 ? 00:00:00 /bin/bash
root 33 0 0 15:41 ? 00:00:00 /bin/bash
root 46 33 0 15:41 ? 00:00:00 ps -ef

或许你也发现使用docker exec、nsenter进入容器后,执行exit退出容器,容器并不会关闭。但是使用docker attach进入容器,输入exit退出容器后,容器也会自动终止。你可以想想为什么。因为除了attach,nsenter和exec实际中都是开了一个新的shell在执行。而attach是使用容器本身启动的/bin/bash,这个shell环境退出了。那么容器就自动退出了。所以Docker的魔咒来了:docker容器只能而且必须在前台运行一个进程,如果进程退出,容器就关闭。当然如果你想在Docker容器中启动多进程也是有办法的,我们后面会讲到。

删除容器

可以使用 docker rm 来删除一个处于终止状态的容器。 例如

[root@docker ~]# docker rm mydocker

如果要删除一个运行中的容器,可以添加-f参数。Docker会发送 SIGKILL信号给容器。

学习中的小技巧

如果你在学习和测试的过程中,经常因为启动非常多的容易想删除也很难,下面列举了几个小技巧,可以快速的帮我们进行容器的清理。

容器停止后就自动删除:

docker run --rm centos /bin/echo "One"

杀死所有正在运行的容器:

docker kill $(docker ps -a -q)

删除所有已经停止的容器:

docker rm $(docker ps -a -q)

删除所有未打 dangling 标签的镜像

docker rmi $(docker images -q -f dangling=true)

删除所有镜像

docker rmi $(docker images -q)

如果你觉得名称很长,不容易记,还可以为这些命令创建别名。

杀死所有正在运行的容器.

alias dockerkill='docker kill $(docker ps -a -q)'

删除所有已经停止的容器.

alias dockerclean='docker rm $(docker ps -a -q)'

删除所有未打标签的镜像.

alias dockercleani='docker rmi $(docker images -q -f dangling=true)'

删除所有已经停止的容器和未打标签的镜像.

alias dockerclean='dockercleanc || true && dockercleani'

注意:生产环境一定要慎用!!!

最新文章

  1. 下载旧版本的NDK
  2. Character Timing for T=0
  3. 【leetcode】Reorder List (middle)
  4. Centos7 Apache 2.4.18编译安装
  5. 如何在windows7上安装启明星系统。
  6. Python文件操作详解
  7. hduacm 3183 rmq
  8. Apache Zeppelin
  9. ADO.NET 学生管理
  10. VMware WorkStation9.0虚拟机如何运行WINPE
  11. 数据结构与算法 —— 链表linked list(01)
  12. 关于Http
  13. python3 OrderedDict类(有序字典)
  14. Android编码学习之Fragment
  15. PKUWC2019游记&amp;&amp;WC2019游记
  16. How to remove live visual tree?
  17. 20155337《网络对抗》Exp5 MSF基础应用
  18. json对象按时间排序
  19. php-fpm打开错误日志的配置
  20. 11.python3标准库--使用进程、线程和协程提供并发性

热门文章

  1. 通过Module读取寄存器的值
  2. IntelliJ快捷键记录
  3. Day 18 :面向对象[基础,继承,组合]类的增删改查
  4. linux网卡驱动更新方法
  5. C# WinForm 第一个项目控件使用心得
  6. velocity 相关
  7. spring mvc 配置后,web中的html页面报404,该怎么处理
  8. Pregel的应用实例——单源最短路径
  9. Linux 中 sqlite3 基本操作
  10. Mysql流程解析