【学习笔记】Docker基础实战教程一:入门

Docker是一套以容器技术为核心的思想和一套标准化的体系,是IT领域的“集装箱”

Hello Docker!

镜像

  • 镜像可以理解为一个打包了运行环境的特殊文件系统,它包含了容器启动运行所需的所有信息,包括运行程序和配置数据等。

  • 镜像不包含任何动态数据,其内容在构建之后也不会改变。

  • 例如,一个官方的Ubuntu14.04镜像,就包含了一套完整的Ubuntu14.04最小系统的root文件系统。

容器

  • 镜像和容器的关系,类似于面向对象程序设计中的类和实例一样,镜像是静态的定义,而容器是镜像运行时的实体,可以看成是一个具备某个运行环境的非常轻量的虚拟机。

  • 容器可以被创建、启动、停止和删除等。

  • 在创建容器时,需要显示地为容器指定镜像。指定镜像之后,容器就具备了镜像中保存的运行环境了。

  • 例如,可以为容器指定Ubuntu14.04的镜像,然后该容器就具备Ubuntu14.04的运行环境了。

Docker Registry

仓库(Repository)是集中存放镜像的地方。另外一个非常相似的单词Registry是注册服务器(例如Docker Hub就是一个官方的Registry)。注册服务器是管理仓库的具体服务器,每个服务器上可以有多个仓库,而每个仓库下面有多个镜像。

从这方面来说,仓库可以被认为是一个具体的项目或目录。例如对于仓库地址dl.dockerpool.com/ubuntu来说,dl.dockerpool.com 是注册服务器地址,ubuntu 是仓库名。(一般而言,一个仓库会存放同一种类型的镜像,例如ubuntu的仓库。)

一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。通常,一个仓库会包含同一个软件不同版本的镜像会,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。

以 Ubuntu 镜像为例, ubuntu是仓库的名字,其内包含有不同的版本标签,比如,14.04 , 16.04 。我们可以通过 ubuntu:14.04 ,或者 ubuntu:16.04来具体指定所需哪个版本的镜像。如果忽略了标签,比如ubuntu ,那将视为ubuntu:latest 。

仓库名经常以两段式路径形式出现,比如training/webapp,前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名。

Docker使用的基本过程

  1. 获取一个镜像;
    在安装完Docker服务之后,本地是没有任何镜像的,所以首先需要获取所需要的镜像。

  2. 基于该镜像创建并启动一个容器;
    在创建容器时也可以设置容器的启动命令,该命令会在容器启动时执行

  3. 进入该容器,执行“程序”。

    • 在容器成功创建并启动之后,该容器就具备了ubuntu的运行环境。我们可以进入该容器内部,并在其内部执行任何在ubuntu系统上的程序了。
    • 这里的“程序”可以是“Linux命令”、“shell脚本”、“C++程序”等。

示例

docker pull busybox:latest
docker run --name zgh busybox:latest echo "Hello Docker"
  • 第一条命令:获取一个名为busybox:latest的镜像。这条命令会从Docker Hub官方镜像仓库获取一个名为busybox:latest的镜像(busybox的最新版),并把它下载到宿主机。其中busybox是最小的Linux系统。

  • 第二条命令: 创建并启动一个容器,并执行相应命令。首先,–name设置容器的名字为zgh,然后为容器指定了busybox:latest作为启动镜像,最后设置了该容器的启动命令为echo “Hello Docker”。容器启动并输出 “Hello Docker”后,将其停止。

  • 其实我们也可以去掉第一条命令,直接使用第二条命令即可完成同样的功能。后台在执行命令时,发现本地没有busybox:latest镜像,会首先自动执行docker pull busybox:latest,将busybox:latest镜像下载到宿主机,然后再以busybox镜像作为基础,创建一个名为first_docker_container的镜像,并执行echo “Hello Docker”命令。

拉取镜像

在Docker的官方镜像仓库Docker Hub中保存了各种各样的镜像,这些镜像中保存了各种各样的运行环境。

例如包含Linux运行环境的“ubuntu”镜像、“centos”镜像、“busybox”镜像等,提供数据库服务的“mysql”镜像、“o\fracle”镜像、“redis”镜像等。提供程序运行环境的“java”镜像、“python”镜像、“c++”镜像等等。

基本上我们日常工作所需要的运行环境在Docker Hub中都会有对应的镜像(Docker Hub官网:https://hub.docker.com/ )

(这些镜像不是凭空出现的,这是镜像构建者们辛勤的劳动成果。每一个Docker的使用者都应该感谢这些镜像构建者们!!)

但是在安装完Docker之后,本地是没有任何镜像的。下面介绍如何从Docker Hub中拉取镜像(或者说下载镜像)。

命令

docker pull [OPTIONS] <仓库名>:<标签>
  • 默认情况下,使用docker pull命令,会从官方的Docker Hub库中将镜像拉取到本地。
  • docker pull:Docker拉取镜像的命令关键词;
  • [OPTIONS]:命令选项;
  • 仓库名:仓库名的格式一般为<用户名>/<软件名>。对于Docker Hub,如果不指定用户名,则默认为library,即官方镜像;
  • 标签:标签是区分镜像不同版本的一个重要参数,<仓库名>:<标签>会唯一确定一个镜像。默认为latest

(在Docker Hub中有很多个镜像仓库,一般情况下会将同一类型的镜像放在同一个仓库中,例如在一个ubuntu仓库中由很多个ubuntu镜像组成,包括ubuntu:14.04、ubuntu:16.04、ubuntu:latest等等镜像)。

设置镜像加速器

#以root用户执行以下操作
mkdir -p /etc/docker
tee /etc/docker/daemon.json <<-'EOF'
{#下面的URL可以替换为你自己的阿里云加速地址
"registry-mirrors": ["https://jxus37ad.mirror.aliyuncs.com "]
}
EOF
systemctl daemon-reload
systemctl restart docker

由于“伟大的墙”的原因,在国内从Docker Hub中拉取镜像的速度可能会比较慢,国内很多云服务商都提供了镜像加速器服务,例如阿里、网易等等。
以Linux系统配置阿里云加速器为例,只需要将下面的命令复制到Linux的终端,以root用户的身份执行之后,就成功的配置了阿里云加速器了!

启动一个容器

启动容器有两种方式,

  • 一种是基于镜像新建一个容器并启动,
  • 另外一个是将在终止状态(stopped)的容器重新启动。

第一种方式:新建并启动

docker run [OPTIONS] 镜像名 [COMMAND] [ARG]
  • docker run命令会基于指定的镜像创建一个容器并且启动它
  • OPTIIONS: 命令选项,最常用的包括-d后台运行容器并返回容器ID,-i以交互模式运行容器,-t为容器分配一个伪输入终端,--name指定启动容器的名称。更多选项请参考Docker帮助文档;
  • 镜像名: 以<仓库名>:<标签>的方式来指定;
  • COMMAND: 设置启动命令,该命令在容器启动后执行;
  • ARG: 其他一些参数。

docker run背后的工作:

  1. 检查本地是否存在指定的镜像,不存在就从公有仓库下载启动;
  2. 利用镜像创建并启动一个容器;
  3. 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层;
  4. 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去;
  5. 从地址池配置一个ip地址给容器;
  6. 执行用户指定的启动命令;
  7. 执行完毕后容器被终止。

第二种方式:启动一个已经终止的容器

虽然Docker容器是非常轻量的,这意味着一般情况下,我们在启动完容器并完成操作之后都会将容器删除掉。但是有些时候我们会进入之前创建的容器,而docker run每次都会创建一个新容器,显然不符合我们的需求。这种时候,可以使用docker start命令,使用容器名或者容器id启动一个已经终止的容器。

docker start [OPTIONS] 容器 [容器2...]
  • docker start: Docker启动容器的命令关键词;
  • OPTIIONS: 命令选项;
  • 容器: 需要启动的容器,该容器用“容器ID”或“容器名”表示,如果指定了多个容器,那么就将这些容器都启动。

查看容器信息

docker ps
  • 可以查看容器的信息,包括容器ID,基础镜像,启动命令,创建时间,当前状态,端口号,容器名字。
  • 如果不加任何参数,只执行docker ps,将会显示所有运行中的容器。
docker ps –a
  • 可以查看Docker环境中所有的容器,包括已经停止的容器。

停止一个容器

docker stop [OPTIONS] Container [Container ...]
  • docker stop: Docker停止容器的命令关键词;
  • OPTIONS:命令选项,其中-t指定等待多少秒后如果容器还没终止,就强行停止,默认等待10秒;
  • Container:需要启动的容器,该容器用“容器ID”或“容器名”表示,如果指定了多个容器,那么就将这些容器都启动。

实际工作中,执行docker stop可能并不会立即终止容器,而是需要等待一段时间。
前面我们说过,容器实际上是一个进程。而执行docker stop之后,首先会向容器的主进程发送一个SIGTERM信号,让主进程释放资源保存状态,尝试自己终止。
但当等待时间超过了-t设置的时间后,会向容器的主进程发送一个SIGKILL信号,使容器立即终止。

在什么情况下容器启动后会立即终止?

实际情况中,除了使用docker stop命令来强制地终止一个容器以外,当容器的启动命令终结时,容器也自动会终止。

之前我们介绍过Docker容器是一个进程,实际上它以sh作为主进程。如果主进程停止了,那么容器也就停止了。
而如果容器的“启动命令”执行完之后,由于主进程没有命令继续执行,所以主进程会停止,容器也就因此而停止了

如何才能使容器启动后不立即终止?

如果容器的sh主进程不停止,是不是以为这容器就不会停止?答案是肯定的。因此,如果使启动命令不能执行完毕,或者在执行完启动命令后,容器的sh主进程不停止,那么容器在启动后就不会立即终止了!

将启动命令设置为“启动一直运行的子进程

docker run --name zgh -it ubuntu /bin/bash

执行完这条命令后,创建并启动容器之后,执行/bin/bash,会启动一个子进程,此时父进程(也就是容器的主进程sh)会进入sleep状态,由于sleep状态不是终止状态,所以容器会继续运行。

为什么在容器中输入exit或者执行ctrl D后,容器将会终止呢,这是因为exit会退出(结束)当前进程,也就是/bin/bash,由于子进程结束,sh主进程恢复到运行态,然而由于没有命令需要继续执行,所以sh主进程结,因此容器终止。

进入一个容器

有些时候,需要让容器在后台运行而不是直接把“启动命令”的结果输出在当前宿主机下。此时,可以通过添加-d参数来实现。

举个例子,假如不使用-d参数执行下面这条命令:

docker run ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"

那么会一直在控制台输出hello world,如下图所示:

docker run ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"
hello world
hello world
hello world
...

但是如果使用了-d参数,此时容器会在后台运行并且不会将输出结果输出到控制台。如下图所示:

docker run -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"
ccd644424bffed71747e2a36977d70745cc211e7dac71006437ca52914c1b743

返回了容器ID,

一般情况下,前4位就能唯一标识一个容器了

如上,ccd6就是代表容器ID以ccd6开头的容器

进入一个docker容器的几种方法

  1. 使用ssh登陆进容器;
  2. 使用nsenter、nsinit等第三方工具;
  3. 使用docker本身提供的工具。

Docker目前主要提供了docker attachdocker exec两个命令。

docker attach containerId|containerName
  • 一般情况下,输入容器ID的前4位即可
  • 使用docker attach进入了该容器内部,实际上就是进入容器“启动命令”的终端
docker exec [options] containerName|containerId command [arg]
  • docker exec命令可以在一个运行的容器内部执行一条命令,
  • 例如执行docker exec aec0 mkdir dir1后,就在容器中创建了一个dir1的文件夹。
  • 补充:aeco代表容器ID
  • 除此以外,还可以在容器中启动一个新的bash,例如执行了docker exec -it aec0 /bin/bash,在容器内部启动了一个新的bash终端,并使用-it为其分配一个伪终端绑定到标准输出上。

attach与exec的主要区别

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

删除容器

随着我们创建的容器越来越多,容器的管理越来越难。而且一般情况下,容器都是在使用完成后立即就删除掉,这时候就需要用到“删除容器”了。

删除一个处于终止状态的容器

docker rm containName|containId
  • 请留意,在不加任何参数的情况下,docker rm只能删除处于终止状态的容器。

删除一个正在运行的容器

有两种方式:

  • 第一种,先执行docker stop停止该容器,然后使用docker rm删除掉;
  • 第二种,执行docker rm –f命令,强制删除。

删除所有处于终止状态的容器

docker rm $(docker ps -a -q)

我们知道docker ps –a命令可以查看所有容器的信息。而docker ps –a –q只查看所有容器的containerId。

在Linux中,将命令放在$()中,会执行命令并返回命令的执行结果。因此$( docker ps -a -q)会返回所有容器的container id,

而docker rm只能干掉终止的容器,而如果用docker rm删除正在运行的容器时,将不能删除掉。

所以可以使用docker rm $(docker ps -a -q)来删除所有处于终止状态的容器。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章