Docker 学习入门

摘自:https://www.cnblogs.com/chiangchou/p/docker.htmlhtml

 

 


1、Docker 简介

一、什么是 Docker

Docker 是使用最普遍的开源容器引擎,它完全释放了计算虚拟化的威力,极大提升了应用的运行效率,下降了云计算资源供应的成本! 使用 Docker,可让应用的部署、测试和分发都变得史无前例的高效和轻松!linux

Docker 使用 Google 公司推出的 Go 语言 进行开发实现,基于 Linux 内核的 cgroup,namespace,以及 AUFS 类的 Union FS 等技术,对进程进行封装隔离,属于操做系统层面的虚拟化技术。因为隔离的进程独立于宿主和其它的隔离的进程,所以也称其为容器。nginx

Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的建立和维护。使得 Docker 技术比虚拟机技术更为轻便、快捷。c++

二、为何要用 Docker

① 更高效的利用系统资源:因为容器不须要进行硬件虚拟以及运行完整操做系统等额外开销,Docker 对系统资源的利用率更高。git

② 更快速的启动时间:Docker 容器应用,因为直接运行于宿主内核,无需启动完整的操做系统,所以能够作到秒级、甚至毫秒级的启动时间。github

③ 一致的运行环境:Docker 的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性。redis

④ 持续交付和部署:使用 Docker 能够经过定制应用镜像来实现持续集成、持续交付、部署。一次建立或配置,能够在任意地方正常运行。sql

⑤ 更轻松的迁移:Docker 确保了执行环境的一致性,使得应用的迁移更加容易。Docker 能够在不少平台上运行,不管是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。docker

三、Docker 基本组成

① 镜像(Images)

Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建以后也不会被改变。

Docker 设计时,充分利用 Union FS 的技术,将其设计为分层存储的架构,Docker 镜像由多层文件系统联合组成。镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在本身这一层。

② 容器(Container)

镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 类 和 实例 同样,镜像是静态的定义,容器是镜像运行时的实体。容器能够被建立、启动、中止、删除、暂停等。

容器的实质是进程,但与直接在宿主执行的进程不一样,容器进程运行于属于本身的独立的 命名空间。所以容器能够拥有本身的 root 文件系统、本身的网络配置、本身的进程空间,甚至本身的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操做同样。

每个容器运行时,是以镜像为基础层,在其上建立一个当前容器的存储层,咱们能够称这个为容器运行时读写而准备的存储层为容器存储层。容器存储层的生存周期和容器同样,容器消亡时,容器存储层也随之消亡。所以,任何保存于容器存储层的信息都会随容器删除而丢失。
按照 Docker 最佳实践的要求,容器不该该向其存储层内写入任何数据,容器存储层要保持无状态化。全部的文件写入操做,都应该使用 数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。
数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。所以,使用数据卷后,容器能够随意删除、从新 run ,数据却不会丢失。

③ 镜像仓库(Registry)

镜像仓库是一个集中的存储、分发镜像的服务。一个 Docker Registry 中能够包含多个仓库(Repository);每一个仓库能够包含多个标签(Tag);每一个标签对应一个镜像。
一般,一个仓库会包含同一个软件不一样版本的镜像,而标签就经常使用于对应该软件的各个版本。咱们能够经过 <仓库名>:<标签> 的格式来指定具体是这个软件哪一个版本的镜像。若是不给出标签,将以 latest 做为默认标签。

最常使用的 Registry 公开服务是官方的 Docker Hub,这也是默认的 Registry,并拥有大量的高质量的官方镜像。用户还能够在本地搭建私有 Docker Registry。Docker 官方提供了 Docker Registry 镜像,能够直接使用作为私有 Registry 服务。

2、Docker 安装

Docker 版本包含 社区版和企业版,咱们平常使用社区版足够。Docker 社区版各个环境的安装参考官方文档:https://docs.docker.com/install/。后面的学习在 Linux CentOS7 上测试。

一、CentOS7 安装步骤

CentOS 安装参考官方文档:https://docs.docker.com/install/linux/docker-ce/centos/

① 卸载旧版本

# yum remove docker docker-common docker-selinux

② 安装依赖包

# yum install -y yum-utils device-mapper-persistent-data lvm2

③ 安装 Docker 软件包源

# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

④ 安装 Docker CE

# yum install docker-ce

⑤ 启动 Docker 服务

# systemctl start docker

⑥ 设置开机启动

# systemctl enable docker

⑦ 验证安装是否成功

# docker -v
# docker info

二、Docker 命令

经过 --help 参数能够看到 docker 提供了哪些命令,能够看到 docker 的用法是 docker [选项] 命令 。

命令有两种形式,Management Commands 是子命令形式,每一个命令下还有子命令;Commands 是直接命令,至关于子命令的简化形式。

继续查看 Management Commands 有哪些子命令,例如查看 image 的子命令。docker image ls 等同于 docker images,docker image pull 等同于 docker pull。

3、镜像管理

一、镜像简介

镜像包含了一个软件的运行环境,是一个不包含Linux内核而又精简的Linux操做系统,一个镜像能够建立N个容器。

镜像是一个分层存储的架构,由多层文件系统联合组成。镜像构建时,会一层层构建,前一层是后一层的基础。

从下载过程当中能够看到,镜像是由多层存储所构成。下载也是一层层的去下载,并不是单一文件。下载过程当中给出了每一层的 ID 的前 12 位。而且下载结束后,给出该镜像完整的 sha256 的摘要,以确保下载一致性。

经过 docker history <ID/NAME> 查看镜像中各层内容及大小,每层会对应着 Dockerfile 中的一条指令。

因为 Docker 镜像是多层存储结构,而且能够继承、复用,所以不一样镜像可能会由于使用相同的基础镜像,从而拥有共同的层。因为 Docker 使用 Union FS,相同的层只须要保存一份便可,所以实际镜像硬盘占用空间极可能要比这个列表镜像大小的总和要小的多。

二、镜像管理

Docker 运行容器前须要本地存在对应的镜像,若是镜像不存在本地,Docker 会从镜像仓库下载,默认是 Docker Hub 公共注册服务器中的仓库。

Docker Hub 是由 Docker 公司负责维护的公共注册中心,包含大量的优质容器镜像,Docker 工具默认从这个公共镜像库下载镜像。下载的镜像如何使用能够参考官方文档。地址:https://hub.docker.com/explore

若是从 Docker Hub 下载镜像很是缓慢,能够先配置镜像加速器,参考:https://www.daocloud.io/mirror

Linux下经过如下命令配置镜像站:

# curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://f1361db2.m.daocloud.io

# systemctl restart docker

① 搜索镜像 :docker search <NAME> [选项]

OFFICIAL:是否官方版本;

 ② 下载镜像 :docker pull [选项] [Docker Registry地址]<仓库名>:<标签>

Docker Registry地址:地址的格式通常是 <域名/IP>[:端口号] 。默认地址是Docker Hub。

仓库名:仓库名是两段式名称,既 <用户名>/<软件名> 。对于 Docker Hub,若是不给出用户名,则默认为 library ,也就是官方镜像。

③ 列出本地镜像 :docker images [选项]

TAG:标签版本;IMAGE ID:镜像ID;SIZE:镜像大小;

查看虚悬镜像(镜像既没有仓库名,也没有标签,显示为 <none>):docker images -f dangling=true

默认的 docker images 列表中只会显示顶层镜像,若是但愿显示包括中间层镜像在内的全部镜像:docker images -a

只列出镜像ID:docker images -q

列出部分镜像:docker images redis 

以特定格式显示:docker images --format "{{.ID}}: {{.Repository}}"

④ 给镜像打 Tag :docker tag <IMAGE ID> [<用户名>/]<镜像名>:<标签>

镜像的惟一标识是其 ID 和摘要,而一个镜像能够有多个标签。

⑤ 删除本地镜像 :docker rmi [选项] <镜像1> [<镜像2> ...]

<镜像> 能够是镜像短 ID、镜像长 ID、镜像名或者镜像摘要。

删除镜像的时候,其实是在要求删除某个标签的镜像。因此首先须要作的是将知足咱们要求的全部镜像标签都取消,这就是咱们看到的Untagged 的信息。

镜像是多层存储结构,所以在删除的时候也是从上层向基础层方向依次进行判断删除。镜像的多层结构让镜像复用变得很是容易,所以颇有可能某个其它镜像正依赖于当前镜像的某一层。这种状况,不会触发删除该层的行为。直到没有任何层依赖当前层时,才会真实的删除当前层。

除了镜像依赖之外,还须要注意的是容器对镜像的依赖。若是有用这个镜像启动的容器存在(即便容器没有运行),那么一样不能够删除这个镜像。若是这些容器是不须要的,应该先将它们删除,而后再来删除镜像。

⑥ 批量删除镜像

删除全部虚悬镜像:docker rmi $(docker images -q -f dangling=true)

删除全部仓库名为  redis  的镜像:docker rmi $(docker images -q redis)

删除全部在  mysql:8.0  以前的镜像:docker rmi $(docker images -q -f before=mysql:8.0)

⑦ 导出镜像:docker save -o <镜像文件> <镜像>

能够将一个镜像完整的导出,就能够传输到其它地方去使用。

⑧ 导入镜像:docker load -i <镜像文件>

4、容器管理

一、建立容器

启动容器有两种方式,一种是基于镜像新建一个容器并启动,另一个是将在终止状态(stopped)的容器从新启动。Docker 容器很是轻量级,不少时候能够随时删除和新建立容器。

建立容器的主要命令为 docker run (或 docker container run),经常使用参数以下:

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

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

① 建立并进入容器:docker run -ti <IMAGE ID OR NAME>  /bin/bash

建立容器,经过 -ti 参数分配一个 bash 终端,并进入容器内执行命令。退出容器时容器就被终止了。

② 容器后台运行:docker run -d <IMAGE ID OR NAME>

容器是否会长久运行,是和 docker run 指定的命令有关,即容器内是否有前台进程在运行,和  -d  参数无关。一个容器必须有一个进程来守护容器才会在后台长久运行。

例如经过 -d 参数后台运行 centos,容器建立完成后将退出。而经过 -ti 分配一个伪终端后,容器内将有一个 bash 终端守护容器,容器不会退出。

③ 进入容器:docker exec -ti <CONTAINER ID> bash

④ 指定端口:docker run -d -p <宿主机端口>:<容器内端口> <IMAGE ID>

经过 -p 参数指定宿主机与容器内的端口映射,若是不指定宿主机端口,将会随机映射一个宿主机端口。映射好端口后,宿主机外部就能够经过该端口访问容器了。

⑤ 宿主机重启时自动重启容器:docker run -d --restart always <IMAGE ID> 

宿主机重启时,docker 容器默认不会自动启动,能够经过 --restart=always 设置自动重启。

二、容器资源限制

容器资源限制主要是对内存的限制和使用CPU数量的限制,经常使用选项以下:

① 使用例子

1) 限制容器最多使用500M内存和100M的Swap,并禁用OOM Killer。注意 --memory-swap 的值为 --memory 的值加上 Swap 的值。

docker run -d --name nginx_1 --memory="500m" --memory-swap="600m" --oom-kill-disable nginx

若是 memory 小于等于 memory-swap,表示不使用Swap;若是 memory-swap="-1" 表示能够无限使用Swap;若是不设置 memory-swap,其值默认为 memory 的2倍。

2) 容许容器最多使用一个半的CPU:docker run -d --name nginx_2 --cpus="1.5" nginx

3) 容许容器最多使用 50% 的CPU:docker run -d --name nginx_3 --cpus=".5" nginx

② 查看容器资源使用统计:docker stats <CONTAINER ID>

经过 docker stats 能够实时查看容器资源使用状况。若是不对容器内存或CPU加以限制,将默认使用物理机全部内存和CPU。一般状况下,为了安全必定要限制容器内存和CPU,不然容器内程序遭到攻击,可能无限占用物理机的内存和CPU。

三、容器经常使用命令

① 中止容器:docker stop <CONTAINER ID>

② 重启容器:docker start <CONTAINER ID>

③ 删除容器

删除已中止的容器:docker rm <CONTAINER ID>

强制删除运行中的容器:docker rm -f <CONTAINER ID>

批量删除Exited(0)状态的容器:docker rm $(docker ps -aq -f exited=0)

批量删除全部容器:docker rm -f $(docker ps -aq)

④ 查看容器日志:docker logs <CONTAINER ID OR NAMES>

⑤ 查看容器详细信息:docker inspect <CONTAINER ID>

⑥ 列出或指定容器端口映射:docker port <CONTAINER ID>

⑦ 显示一个容器运行的进程:docker top <CONTAINER ID>

⑧ 拷贝文件/文件夹到容器:docker cp <dir> <CONTAINER ID>:<dir>

⑨ 查看容器与镜像的差别:docker diff <CONTAINER ID>

5、管理应用程序数据

容器删除后,里面的数据将一同被删除,所以须要将容器内常常变更的数据存储在容器以外,这样删除容器以后数据依然存在。

Docker 提供三种方式将数据从宿主机挂载到容器中:

  • volumes:由 Docker 管理的数据卷,是宿主机文件系统的一部分(/var/lib/docker/volumes)。是保存数据的最佳方式。
  • bind mounts:将宿主机上的文件或目录挂载到容器中,一般在容器须要使用宿主机上的目录或文件时使用,好比搜集宿主机的信息、挂载宿主机上的 maven 仓库等。
  • tmpfs:挂载存储在主机系统的内存中,而不会写入主机的文件系统。若是不但愿将数据持久存储在任何位置,可使用 tmpfs,同时避免写入容器可写层提升性能。这种方式使用比较少。

一、Volume

① 管理卷

建立数据卷:docker volume create <volume_name>

查看数据卷列表:docker volume ls

查看数据卷详细信息:docker volume inspect <volume_name>

建立的数据卷默认在宿主机的 /var/lib/docker/volumes/ 下

② 建立容器时指定数据卷

1) 经过 --mount 方式:--mount src=<数据卷名称>,dst=<容器内的数据目录>,注意逗号之间不能有空格

docker run -d --name nginx_1 --mount src=nginx_html,dst=/usr/share/nginx/html nginx

2) 经过 -v 方式:-v <数据卷名称>:<容器内的数据目录>

docker run -d --name nginx_2 -v nginx_html:/usr/share/nginx/html nginx

以上两种方式,--mount 更加通用直观,-v 是老语法的方式。若是对应的数据卷不存在,将自动建立数据卷。若是挂载目标在容器中非空,则该目录现有内容会自动同步到数据卷中。

③ 删除数据卷:docker volume rm <volume_name>

数据卷是独立于容器的生命周期的,删除容器是不会删除数据卷的,除非删除数据卷,删除数据卷以后数据也就丢失了。

若是数据卷正在被某个容器使用,将不能被删除,须要先删除使用此数据卷的全部容器以后才能删除数据卷。

④ Volume 特色及使用场景

  • 多个容器能够同时挂载相同的卷,可用于多个运行容器之间共享数据。
  • 当容器中止或被删除后,数据卷依然存在。当明确删除卷时,卷才会被删除。
  • 能够将容器的数据存储在远程主机或其它存储上。
  • 将数据从一台 docker 主机迁移到另外一台主机时,先中止容器,而后备份卷的目录 /var/lib/docker/volumes

二、Bind Mounts

① 建立容器时绑定数据卷

1) 经过 --mount 方式:--mount type=bind,src=<宿主机目录>,dst=<容器内的数据目录>,注意逗号之间不能有空格

docker run -d --name nginx_1 --mount type=bind,src=/data/nginx/html,dst=/usr/share/nginx/html nginx

2) 经过 -v 方式:-v <宿主机目录>:<容器内的数据目录>

docker run -d --name nginx_2 -v /data/nginx/html:/usr/share/nginx/html nginx

以上两种方式,若是源文件/目录不存在,不会自动建立容器,会抛出错误。与 volume 方式相比,若是挂载目标在容器中非空,则该目录现有内容将被隐藏,能够理解成使用宿主机的目录覆盖了容器中的目录,新增的数据会同步。

② Bind Mounts 特色及使用场景

  • 从主机共享配置文件到容器。默认状况下,挂载主机 /etc/resolv.conf 到每一个容器,提供 DNS 解析。
  • 在 docker 主机上的开发环境和容器之间共享源代码。例如,能够将 maven target 目录挂载到容器中,每次在 docker 主机上构建maven项目时,容器均可以访问构建好的项目包。
  • 当 docker 主机的文件或目
  • 录结构保证与容器所需的绑定挂载一致时,例如容器中须要统计主机的一些信息,能够直接将主机的某些目录直接挂载给容器使用。

6、容器网络

一、Docker 网络模式

① bridge:--net=bridge

默认网络,docker 启动后会建立一个 docker0 网桥,默认建立的容器会添加到这个网桥中。

建立容器时不指定网络模式,默认使用 bridge 方式,经过容器网络配置能够看到会默认分配一个 docker0 的内网IP。

② host:--net=host

容器不会得到一个独立的 network namespace,而是与主机共用一个。这就意味着容器不会有本身的网卡信息,而是使用宿主机的。容器除了网络,其它都是隔离的。

能够看到 host 网络模式下,容器网络配置与宿主机是同样的。那么容器内应用的端口将占用宿主机的端口。

③ none:--net=none

获取独立的 network namespace,但不为容器进行任何网络配置,须要咱们手动配置。应用场景比较少。

④ container:--net=container:<CONTAINER NAME/ID>

与指定的容器使用同一个 network namespace,具备一样的网络配置信息,两个容器除了网络,其它都是隔离的。

1) 建立容器,并映射 9090 端口到容器的 80 端口,进入容器内,经过 netstat -antp 能够看到没有端口链接信息

2) 建立 nginx 容器,并使用 net_container 容器的网络。能够看到 net_container 容器内已经在监听 nginx 的80端口了,并且经过 映射的 9090 端口能够访问到 nginx 服务。

⑤ 自定义网络

与默认的bridge原理同样,但自定义网络具有内部DNS发现,能够经过容器名或者主机名进行容器之间网络通讯

首先建立一个自定义网络,建立两个容器并加入到自定义网络,在容器中就能够互相连通。

二、容器网络访问原理

当 Docker 启动时,会自动在主机上建立一个 docker0 虚拟网桥(其上有一个 docker0 内部接口),其实是Linux 的一个 bridge,能够理解为一个软件交换机。它在内核层连通了其余的物理或虚拟网卡,这就将全部容器和本地主机都放到同一个物理网络。

每次建立一个新容器的时候,Docker 从可用的地址段中选择一个空闲的 IP 地址分配给容器的 eth0 端口。使用本地主机上 docker0 接口的 IP 做为全部容器的默认网关。

当建立一个 Docker 容器的时候,同时会建立一对 veth pair 接口(当数据包发送到一个接口时,另一个接口也能够收到相同的数据包)。这对接口一端在容器内,即 eth0 ;另外一端在本地并被挂载到 docker0 网桥,名称以 veth 开头。经过这种方式,主机能够跟容器通讯,容器之间也能够相互通讯。Docker 就建立了在主机和全部容器之间的一个虚拟共享网络。

7、制做镜像

一、Dockerfile

镜像是多层存储,每一层是在前一层的基础上进行的修改;Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,所以每一条指令的内容,就是描述该层应当如何构建。

咱们所使用的镜像基本都是来自于 Docker Hub 的镜像,直接使用这些镜像是能够知足必定的需求,而当这些镜像没法直接知足需求时,咱们就须要定制这些镜像。

编写 Dockerfile 时,主要会用到以下一些指令:

Dockerfile 中每个指令都会创建一层,在其上执行后面的命令,执行结束后, commit 这一层的修改,构成新的镜像。对于有些指令,尽可能将多个指令合并成一个指令,不然容易产生很是臃肿、很是多层的镜像,不只仅增长了构建部署的时间,也很容易出错。并且Union FS 是有最大层数限制的,好比 AUFS不得超过 127 层。所以镜像构建时,必定要确保每一层只添加真正须要添加的东西,任何无关的东西都应该清理掉。

① FROM

一个 Dockerfile 中 FROM 是必备的指令,而且必须是第一条指令。

格式:FROM <镜像名称>[:<TAG>]

Docker 还存在一个特殊的镜像,名为 scratch 。这个镜像并不实际存在,它表示一个空白的镜像。若是以 scratch 为基础镜像的话,意味着不以任何镜像为基础,接下来所写的指令将做为镜像第一层开始存在。

② RUN

RUN 指令是用来执行命令行命令的。因为命令行的强大能力, RUN 指令在定制镜像时是最经常使用的指令之一。

多个 RUN 指令尽可能合并成一个,使用 && 将各个所需命令串联起来。Dockerfile 支持 Shell 类的行尾添加 \ 的命令换行方式,以及行首 # 进行注释的格式。

格式:

  • shell 格式: RUN <命令> ,就像直接在命令行中输入的命令同样。
  • exec 格式: RUN ["可执行文件", "参数1", "参数2"] ,这更像是函数调用中的格式。

③ COPY

COPY 指令将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置。<源路径> 能够是多个,甚至能够是通配符。<目标路径> 能够是容器内的绝对路径,也能够是相对于工做目录的相对路径。

使用 COPY 指令,源文件的各类元数据都会保留。好比读、写、执行权限、文件变动时间等。

格式:

  • COPY <源路径>,...  <目标路径>
  • COPY ["<源路径1>",... "<目标路径>"]

④ ENV

设置环境变量,不管是后面的其它指令,如 RUN ,仍是运行时的应用,均可以直接使用这里定义的环境变量。

格式:

  • ENV <key> <value>
  • ENV <key1>=<value1> <key2>=<value2>...

⑤ USER

USER 用于切换到指定用户,这个用户必须是事先创建好的,不然没法切换。

格式: USER <用户名>

⑥ EXPOSE

EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会由于这个声明应用就会开启这个端口的服务。

格式:EXPOSE <端口1> [<端口2>...]

⑦ HEALTHCHECK

HEALTHCHECK  指令是告诉 Docker 应该如何判断容器的状态是否正常。经过该指令指定一行命令,用这行命令来判断容器主进程的服务状态是否还正常,从而比较真实的反应容器实际状态。

当在一个镜像指定了 HEALTHCHECK 指令后,用其启动容器,初始状态会为 starting ,在 HEALTHCHECK 指令检查成功后变为 healthy ,若是连续必定次数失败,则会变为 unhealthy

格式:

  • HEALTHCHECK [选项] CMD <命令> :设置检查容器健康情况的命令,CMD 命令的返回值决定了该次健康检查的成功与否: 0 - 成功; 1 - 失败;。
  • HEALTHCHECK NONE :若是基础镜像有健康检查指令,使用这行能够屏蔽掉其健康检查指令

HEALTHCHECK 支持下列选项:

  • --interval=<间隔> :两次健康检查的间隔,默认为 30 秒;
  • --timeout=<时长> :健康检查命令运行超时时间,若是超过这个时间,本次健康检查就被视为失败,默认 30 秒;
  • --retries=<次数> :当连续失败指定次数后,则将容器状态视为unhealthy ,默认 3 次。

⑧ WORKDIR

使用 WORKDIR 指令能够来指定工做目录(或者称为当前目录),之后各层的当前目录就被改成指定的目录,该目录须要已经存在, WORKDIR 并不会帮你创建目录。

在Dockerfile 中,两行 RUN 命令的执行环境是不一样的,是两个彻底不一样的容器。每个 RUN 都是启动一个容器、执行命令、而后提交存储层文件变动。所以若是须要改变之后各层的工做目录的位置,那么应该使用  WORKDIR  指令。

格式:WORKDIR <工做目录路径>  

⑨ VOLUME

容器运行时应该尽可能保持容器存储层不发生写操做,对于数据库类须要保存动态数据的应用,其数据库文件应该保存于卷(volume)中。为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在 Dockerfile 中,咱们能够事先指定某些目录挂载为匿名卷,这样在运行时若是用户不指定挂载,其应用也能够正常运行,不会向容器存储层写入大量数据。

格式:

  • VOLUME ["<路径1>", "<路径2>"...]
  • VOLUME <路径>

这里的路径会在运行时自动挂载为匿名卷,任何向此路径中写入的信息都不会记录进容器存储层,从而保证了容器存储层的无状态化。

⑩ CMD

CMD 指令用于指定默认的容器主进程的启动命令。

格式:

  • shell 格式: CMD <命令>
  • exec 格式: CMD ["可执行文件", "参数1", "参数2"...]

在运行时能够指定新的命令来替代镜像设置中的这个默认命令,跟在镜像名后面的是  command  ,运行时会替换  CMD  的默认值;例如:docker run -ti nginx /bin/bash,"/bin/bash" 就是替换命令。

在指令格式上,通常推荐使用 exec 格式,这类格式在解析时会被解析为 JSON数组,必定要使用双引号,而不要使用单引号。若是使用 shell 格式的话,实际的命令会被包装为 sh -c 的参数的形式执行,如:CMD echo $HOME 会被包装为 CMD [ "sh", "-c", "echo $HOME" ],实际就是一个 shell 进程。

注意:Docker 不是虚拟机,容器中的应用都应该之前台执行。对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出。启动程序时,应要求其之前台形式运行。

⑪ ENTRYPOINT

ENTRYPOINT 的目的和 CMD 同样,都是在指定容器启动程序及参数。 ENTRYPOINT 在运行时也能够替代,不过比 CMD 要略显繁琐,须要经过 docker run 的参数 --entrypoint 来指定。

格式:

  • shell 格式: ENTRYPOINT <命令>
  • exec 格式: ENTRYPOINT ["可执行文件", "参数1", "参数2"...]

当指定了 ENTRYPOINT 后, CMD 的含义就发生了改变,再也不是直接的运行其命令,而是将 CMD 的内容做为参数传给 ENTRYPOINT 指令。ENTRYPOINT 中的参数始终会被使用,而 CMD 的额外参数能够在容器启动时动态替换掉。

复制代码
例如:
ENTRYPOINT ["/bin/echo", "hello"]  

容器经过 docker run -ti <image> 启动时,输出为:hello

容器经过 docker run -ti <image> docker 启动时,输出为:hello docker

将Dockerfile修改成:

ENTRYPOINT ["/bin/echo", "hello"]  
CMD ["world"]

容器经过 docker run -ti <image> 启动时,输出为:hello world

容器经过 docker run -ti <image> docker 启动时,输出为:hello docker
复制代码

二、构建基础镜像

以构建 nginx 基础镜像为例看如何使用 Dockerfile 构建镜像。

① 编写 Dockerfile

复制代码
# 基于 centos:8 构建基础镜像
FROM centos:8
# 做者
MAINTAINER jiangzhou.bo@vip.163.com
# 安装编译依赖的 gcc 等环境,注意最后清除安装缓存以减少镜像体积
RUN yum install -y gcc gcc-c++ make \
    openssl-devel pcre-devel gd-devel \
    iproute net-tools telnet wget curl \
    && yum clean all \
    && rm -rf /var/cache/yum/*
# 编译安装 nginx
RUN wget http://nginx.org/download/nginx-1.17.4.tar.gz \
    && tar zxf nginx-1.17.4.tar.gz \
    && cd nginx-1.17.4 \
    && ./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module \
    && make && make install \
    && rm -rf /usr/local/nginx/html/* \
    && echo "hello nginx !" >> /usr/local/nginx/html/index.html \
    && cd / && rm -rf nginx-1.17.4*
# 加入 nginx 环境变量
ENV PATH $PATH:/usr/local/nginx/sbin
# 拷贝上下文目录下的配置文件
COPY ./nginx.conf /usr/local/nginx/conf/nginx.conf
# 设置工做目录
WORKDIR /usr/local/nginx
# 暴露端口
EXPOSE 80
# daemon off: 要求 nginx 之前台进行运行
CMD ["nginx", "-g", "daemon off;"]
复制代码

② 构建镜像

命令:docker build -t <镜像名称>:<TAG> [-f <Dockerfile 路径>] <上下文目录>

  • 上下文目录:镜像构建的上下文。Docker 是 C/S 结构,docker 命令是客户端工具,一切命令都是使用的远程调用形式在服务端(Docker 引擎)完成。当构建的时候,用户指定构建镜像上下文的路径,docker build 命令得知这个路径后,会将路径下的全部内容打包,而后上传给 Docker 引擎。这样 Docker 引擎收到这个上下文包后,展开就会得到构建镜像所需的一切文件。这样在 COPY 文件的时候,其实是复制上下文路径下的文件。通常来讲,应该将 Dockerfile 以及所需文件置于一个空目录下,并指定这个空目录为上下文目录。
  • Dockerfile 路径:可选,缺省时会寻找当前目录下的 Dockerfile 文件,若是是其它名称的 Dockerfile,可使用 -f 参数指定文件路径。

在 nginx 目录下包含了构建须要的 Dockerfile 文件及配置文件,docker build 执行时,能够清晰地看到镜像的构建过程。构建成功后,就能够在本地看到已经构建好的镜像。

基于构建的镜像启用容器并测试:

③ 构建应用镜像

构件好基础镜像以后,以这个基础镜像来构建应用镜像。

首先编写 Dockerfile:将项目下的 html 目录拷贝到 nginx 目录下

FROM bojiangzhou/nginx:v1
COPY ./html /usr/local/nginx/html

项目镜像构建成功后,运行镜像,能够看到内容已经被替换了。咱们构建好的项目镜像就能够传给其余用户去使用了。

8、镜像仓库

一、Habor

镜像仓库是集中存放镜像的地方。目前 Docker 官方维护了一个公共仓库 Docker Hub,大部分需求,均可以经过在 Docker Hub 中直接下载镜像来实现。

有时候使用 Docker Hub 这样的公共仓库可能不方便,用户能够建立一个本地仓库供私人使用。docker-registry  是官方提供的工具,能够用于构建私有的镜像仓库。

Habor 是由 VMWare 公司开源的容器镜像仓库,Habor 在 docker-registry 上进行了相应的企业级扩展,从而得到了更加普遍的应用。这章学习如何使用 Habor 搭建本地私有仓库。

Harbor 安装及配置要求参考:Installation and Configuration Guide

Harbor 使用文档参考:User Guide

安装 Harbor 前,需确保硬件条件至少 2核4G内存40G的硬盘,本机需已安装 docker、docker-compose、openssl。

二、安装 Docker Compose

Docker Compose 是 Docker 官方编排(Orchestration)项目之一,负责快速在集群中部署分布式应用。使用 Docker Compose 能够轻松、高效的管理容器,它是一个用于定义和运行多容器 Docker 的应用程序工具。它容许用户经过一个单独的 docker-compose.yml 模板文件来定义一组相关联的应用容器为一个项目。Harbor 也是基于 docker compose 编排部署的。

① 安装 Docker Compose 能够经过下面命令自动下载适应版本的 Compose,并为安装脚本添加执行权限

# curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
# chmod +x /usr/local/bin/docker-compose

② 检测安装是否成功

# docker-compose -v

三、安装 Harbor

① 首先从 github 下载二进制包,选择一个最新版本安装:https://github.com/goharbor/harbor/releases

# wget https://storage.googleapis.com/harbor-releases/release-1.9.0/harbor-offline-installer-v1.9.1.tgz

② 解压

# tar zxvf harbor-offline-installer-v1.9.1.tgz
# cd harbor

③ 修改配置文件

# vim harbor.yml

主要修改 hostname 为可访问的域名或IP、修改管理员密码

④ 安装

# ./prepare
# ./install.sh

Harbor 安装成功后,实际上就是经过 docker compose 启动了相关组件的容器

⑤ Harbor 生命周期管理

harbor 基于 docker compose 编排部署,所以可使用 docker-compose 命令来管理 harbor 的生命周期。

首先切到 harbor 根目录下

中止 harbor:docker-compose stop

重启 harbor:docker-compose start

修改配置:

复制代码
# #先中止 harbor
# docker-compose down -v
# #修改 harbor.yml
# vim harbor.yml
# #运行 prepare 填充配置
# ./prepare
# #启动harbor
# docker-compose up -d
复制代码

四、Harbor 简单使用

① 访问 Harbor

访问配置的 hostname 进入 harbor 管理页面。具体如何使用可参考官方文档:User Guide

经过新建项目建立一个项目(bojiangzhou)用于测试。公开项目不需登陆就能够下载镜像,私有的须要登陆;上传镜像则都须要登陆才能上传镜像。

 推送镜像的命令格式能够参考以下:

② 建立用户

若想上传镜像,须要用户登陆,首先在用户管理建立用户:

接着在项目中添加用户成员:

③ 前置配置

上传镜像以前,首先须要将 harbor 仓库配置为 docker 授信的仓库,不然将被拒绝链接:

vim /etc/docker/daemon.json
# 配置以下内容
{
    "registry-mirrors": ["http://f1361db2.m.daocloud.io"],
    "insecure-registries": ["192.168.31.54"]
}

以后重启 docker 和 harbor:

#systemctl restart docker

# cd /docker-test/harbor
# docker-compose up -d

④ 镜像仓库登陆退出

登陆:docker login registry

退出:docker logout registry

⑤ 上传镜像

首先须要给镜像打 Tag:docker tag SOURCE_IMAGE[:TAG] 192.168.31.54/bojiangzhou/IMAGE[:TAG]

接着推送镜像:docker push 192.168.31.54/bojiangzhou/IMAGE[:TAG]

能够看到镜像已经推送到镜像仓库了:

下载仓库镜像:docker pull 192.168.31.54/bojiangzhou/nginx-app:1.0.0

9、图形化管理

Portainer 是一个开源、轻量级 Docker 管理用户页面,基于 Docker API,管理 Docker 主机。通常单机下不会使用图形管理页面,这里简单了解下就好。

一、安装 Portainer

① 建立数据卷:docker volume create portainer_volume

② 启动 Portainer 容器:docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock -v portainer_volume:/data portainer/portainer

二、访问 Portainer

访问 ip:9000,便可进入 Portainer 管理页面,首先须要建立一个管理用户

接着链接本机

链接本地进入后就能够进行容器、镜像等的管理了。

 

--------------------------------------------------------------------------------------------------------------------------------

做者: bojiangzhou
本文版权归做者和博客园共有,欢迎转载,但未经做者赞成必须保留此段声明,且在文章页面明显位置给出原文链接,不然保留追究法律责任的权利。
 
分类:  容器化
标签:  docker容器镜像harbor
相关文章
相关标签/搜索