【Docker】入门

不管是作为开发还是架构,都有必要了解容器技术,它不仅可以帮助我们了解程序运行时的情况,也能在平时给我们软件安装方面的便捷。

由于 Docker 不是用 Java 编写,所以作为 Java 开发只要做到了解、会用的程度就够了,也不需要完全记住它的命令,只要在需要的时候查文档就可。最主要的是要了解容器的一些概念

1. 基础概念

Docker 包括三个概念:镜像(Image)、容器(Container)、仓库(Repository)

1.1 Docker 镜像

镜像是什么

操作系统分为内核和用户空间,对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间的支持。Docker 镜像就相当于是一个 root 文件系统。比如官方镜像 centos:7.6 就包含了完整的一套 centos 7.6 最小系统的 root 文件系统。

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

镜像的分层存储

因为镜像包含操作系统完整的 root 文件系统,其体积往往是庞大的,因此在 Docker 设计时将其设计为分层存储的架构。镜像只是一个虚拟的概念,其实际由一组文件组成,或者说,由多层文件系统联合组成。

镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。在构建镜像的时候,要格外小心,每一层尽量只包含该层需要的东西,任何额外的东西应该在该层构建前清理掉。

分层存储的特性还使得镜像的复用、定制变得更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,来构建新的镜像。

1.2 Docker 容器

容器是什么

镜像和容器的关系,就像 Java 中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

前面说镜像使用的是分层存储,容器也是这样。每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为容器存储层。

容器存储层的生命周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。

如何读写数据

按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作系统,都应该使用 Volumn 数据卷、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或者网络存储)发生读写,其性能和稳定性更高。

数据卷的生命周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行,数据都不会丢失。

1.3 Docker 仓库

仓库是什么

镜像构建完后,可以很容易的在当前的宿主机上运行,但是,如果需要在其他服务器上使用这个镜像,我们就需要一个集中存储、分发镜像的服务,Docker Registry 就是这样的服务。

一个 Docker Registry 中可以包含多个仓库(Repository),每个仓库可以包含多个标签(Tag),每个标签对应一个镜像。

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

以 centos 镜像为例,ecntos 是仓库的名字,期内包含有不同的版本标签,如 6.9、7.5。可以通过 centos:6.9 或者 centos:7.5 来指定具体所有要镜像的版本。如果忽略了标签,如 centos,那将视为 centos:latest。

仓库名经常以两段式路径形式出现,比如 study/nginx,前者往往意味着 Docker Registry 多用户环境下的用户名,后者往往对应软件名。但这并不是绝对的,取决于所使用的具体 Docker Registry 的软件或者服务。

Docker Registry 公开仓库

常用的 Registry 是官方的 Docker Hub,也是默认的 Registry。除此以外,还有 CoreOS 的 Quay.io,CoreOS 相关的镜像存储在这里,Google 的 Google Container Registry,Kubernetes 的镜像使用的就是这个服务。

国内的一些云服务商提供了针对 Docker Hub 的镜像服务,这些镜像服务被称为加速器。常见的有阿里云加速器、DaoCloud 加速器等。

国内也有一些云服务商提供类似于 Docker Hub 的公开服务。比如 网易云镜像服务、DaoCloud 镜像市场、阿里云镜像库等。

Docker Registry 私有仓库

除了使用公开服务以外,用户还可以在本地搭建私有 Docker Registry。Docker 官方提供了 Docker Registry 镜像,可以直接使用作为私有 Registry 服务。

开源的 Docker Registry 镜像只提供了 Docker Registry API 的服务端实现,足以支持 docker 命令,不影响使用。但不包含图形界面,以及镜像维护、用户管理、访问控制等高级功能。在官方的商业化版本 Docker Trusted Registry 中,提供了这些功能。

除了官方的 Docker Registry 外,还有第三方软件实现了 Docker Registry API,甚至提供了用户界面以及一些高级功能。比如:VMWare Harbor 和 Sonatype Nexus。

2. 安装和加速

Docker 在 1.13 版本之后,从2017年3月1日开始,版本的命名规则如下:

项目 说明
版本格式 YY.MM
Stable 版本 每个季度发行
Edge 版本 每个月发行

同时 Docker 划分为 CE 和 EE版本。CE 即社区版(免费,支持周期三个月),EE 即企业版,强调安全,付费使用。

这里以 Centos 7 为例。你也可以查看官方安装教程来安装。

系统要求:
Docker CE 支持 64 位版本 Centos 7,并且要求内核版本不低于 3.10。
查看内核版本:uname -r

卸载旧版本 (没安装过的忽略)
旧版本的 Docker 称为 docker 或者 docker-engine,使用以下命令卸载旧版本:
sudo yum remove docker docker-common docker-selinux docker-engine

2.1 安装

2.1.1 使用 yum 安装

注意:如果你安装的是 Centos minimal,那么需要执行下面的命令来安装必要的依赖包
sudo yum install -y yun-utils device-mapper-persistent-data lvm2

如果安装过程中出现图下错误:

http://mirrors.163.com/centos/7.6.1810/os/x86_64/repodata/repomd.xml: [Errno 14] curl#6 - "Could not resolve host: mirrors.163.com; Unknown error"
Trying other mirror.

应该是 DNS 服务器错误,需要手动设置
vi /etc/resolv.conf
添加如下信息
nameserver 8.8.8.8

设置 docker-ce 的 yum 源
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

安装
sudo yum install docker-ce

2.1.2 使用脚本安装

Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,Centos 系统上可以使用这套脚本安装:
curl -fsSl https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh --mirror Aliyun

执行这个命令后,脚本就会自动将一切准备工作做好,并且把 Docker CE 的 Edge 版本安装好

2.1.3 启动

启动
sudo systemctl start docker

设置开机启动
sudo systemctl enable docker

查看 Docker 版本
docker --version

Docker version 18.09.6, build 481bc77156

查看 Docker 详细信息
docker info

Containers: 1
 Running: 0
 Paused: 0
 Stopped: 1
Images: 1
Server Version: 19.03.1
Storage Driver: overlay2
 Backing Filesystem: xfs
 Supports d_type: true
 Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
 Volume: local
 Network: bridge host ipvlan macvlan null overlay
 Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: bb71b10fd8f58240ca47fbb579b9d1028eea7c84
runc version: 2b18fe1d885ee5083ef9f0838fee39b62d653e30
init version: fec3683
Security Options:
 seccomp
  Profile: default
Kernel Version: 3.10.0-957.el7.x86_64
Operating System: CentOS Linux 7 (Core)
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 927.1MiB
Name: localhost.localdomain
ID: ZKE5:CXUQ:2EQC:GHOP:PP4K:CTSM:FOJQ:CI3P:3MWC:GZ23:VTND:7PU7
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
 127.0.0.0/8
Live Restore Enabled: false

2.1.4 建立 Docker 用户组

默认情况下,docker 命令会使用 unix socket 与 Docker 引擎通讯。但是只有 root 用户和 docker 组的用户才可以访问 Docker 引擎的 Unix socket。一般 Linux 系统上不会直接用 root 用户操作。因此,需要将使用 docker 的用户加如 docker 用户组。

只是学习的话可以跳过该步骤。
建立 docker 组:sudo groupadd docker
将当前用户加入到用户组:sudo usermod -aG docker $USER

2.1.5 测试

启动一个基于 hello-world 的容器,如果没有这个容器,docker 会自动下载然后运行
docker run hello-world

如果输出一下信息,则安装成功:

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete 
Digest: sha256:6540fc08ee6e6b7b63468dc3317e3303aae178cb8a45ed3123180328bcc1d20f
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

2.1.6 删除 docker

卸载
sudo yum remoce docker-ce

删除 docker 镜像
sudo rm -rf /var/lib/docker

2.2 配置镜像加速

使用 docker info 命令能看到目前 docker 是从哪里下载镜像的: Registry: https://index.docker.io/v1/

配置国内的镜像源
修改或新建 daemon.json:vi /ect/docker/daemon.json,添加以下内容

{
    "registry-mirrors": [
        "http://hub-mirror.c.163.com"
    ]
}

加载配置:sudo systemctl daemon-reload
重启:sudo systemctl restart docker

然后再使用 docker info 查看下载地址,其中 出现Registry: https://index.docker.io/v1/就修改成功了

3. 操作命令

3.1 Docker 镜像操作

Docker 运行容器前需要本地存在对应的镜像,如果本地不存在该镜像,Docker 会从镜像仓库下载该镜像。

3.1.1 获取镜像

从 Docker 镜像仓库获取镜像的命令是 docker pull。它的格式为:
docker pull 选项 仓库地址:端口号/仓库名:标签

具体选项可以通过 docker pull --help 命令查看。
镜像名称的格式一般是域名/IP:端口号,默认是 Docker Hub。
仓库名格式为用户名/软件名,对于 Docker Hub,如果不给出用户名,则默认为 library,也就是官方镜像。

docker pull ubuntu:16.04,会从 Docker Hub 的 /library/ubuntu 仓库中拉取标签为16.04的镜像。执行一下看看:

16.04: Pulling from library/ubuntu
f7277927d38a: Downloading 
8d3eac894db4: Download complete 
edf72af6d627: Download complete 
3e4f86211d23: Download complete 
16.04: Pulling from library/ubuntu
f7277927d38a: Pull complete 
8d3eac894db4: Pull complete 
edf72af6d627: Pull complete 
3e4f86211d23: Pull complete 
Digest: sha256:97b54e5692c27072234ff958a7442dde4266af21e7b688e7fca5dc5acc8ed7d9
Status: Downloaded newer image for ubuntu:16.04

修改了镜像仓库之后还是比较快的

3.1.2 运行镜像

有了镜像之后就可以启动并运行一个容器了,可以使用 bash 进行交互式操作,如:
docker run -it --rm ubuntu:16.04 bash

-it:这是两个参数。-t 为终端,让 Docker 分配一个伪终端并绑定到容器的标准输入上,-i 让容器的标准输入保持打开
--rm:表示容器推出之后将其删除,注意这里删除的是容器,不是镜像
ubuntu:16.04:指定使用的镜像
bash:放在镜像后的是命令,这里使用 bash 作为交互式 shell

然后可以通过 exit 推出容器

3.1.3 列出镜像

1.列出镜像docker image ls,包含仓库名、标签、镜像ID、创建时间、占用空间

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              16.04               5e13f8dd4c1a        2 weeks ago         120MB

2.查看镜像、容器、数据卷占用空间docker system df

TYPE                TOTAL               ACTIVE              SIZE                RECLAIMABLE
Images              1                   0                   120.3MB             120.3MB (100%)
Containers          0                   0                   0B                  0B
Local Volumes       3                   0                   357.6MB             357.6MB (100%)
Build Cache         0                   0                   0B                  0B

3.显示虚悬镜像docker image ls -f dangling=true,仓库名称、标签均为<none>的镜像,称为虚悬镜像

现在没有虚悬镜像,我们可以自己创建一个
创建一个文件touch Dockerfile
编辑vi Dockerfile,保存一下内容,将 ubuntu:16.04 作为基础镜像,输出一句话

FROM ubuntu:16.04

CMD echo "鸡你太美"

构建docker build .,不指定参数和名字,就会产生一个虚悬镜像

查看docker image ls,这是就有了一个虚悬镜像

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
<none>              <none>              27a0e5307b97        3 minutes ago       120MB
ubuntu              16.04               5e13f8dd4c1a        2 weeks ago         120MB

删除虚悬镜像docker image prune,一般来说,虚悬镜像已经失去存在的意义,可以随意删除

3.1.4 删除本地镜像

使用 docker image rm [选项] [<镜像1> <镜像2> ...] 来删除,<镜像>可以使镜像段ID、长ID、镜像名或者镜像摘要

使用 docker image ls -q 来配合 docker image rm 可以批量需要删除的镜像
删除所有镜像:docker image rm $(docker image ls -q)
删除所有 ubuntu 镜像:docker image rm $(docker image ls -q ubuntu)
删除所有在 ubuntu:16.04 之前的镜像:docker image rm $(docker image ls -q -f before=ubuntu)

3.2 Docker 容器操作

3.2.1 查看容器

查看所有容器:docker ps -a

3.2.2 启动容器

启动容器分两种,一是基于镜像新建一个容器并启动,二是将终止状态的容器重新启动。

因为 Docker 容器是轻量级的,可以随时删除和新建容器。

新建并启动docker run
新建并启动一个容器,然后输出一句话:docker run ubuntu:16.04 /bin/echo '鸡你太美'

启动已终止的容器docker startdocker container start

启动一个 bash 终端,允许用户进行交互:
docker run -it ubuntu:16.04 /bin/bash

3.2.3 后台运行

通过-d参数表示允许在后台运行
docker run hello-world:会把日志打印在控制台
docker run -d hello-world:不会输出日志,只会打印容器id,可以通过docker logs id来查看日志

注意:容器是否会长久运行,和 docker run 指定的命令有关,和 -d 参数无关,-d 只是表示允许在后台运行

3.2.3 停止容器

使用docker container stop来终止运行的容器
充值状态的容器可以用docker container ls -a查看
处于终止状态的容器,可以使用docker container start重新启动
运行状态的容器,可以使用docker container restart来重启

3.2.4 进入容器

使用 -d 时容器会进入后台,使用docker exec可以进入到运行的容器中:docker exec -it 容器ID /bin/bash

docker exec 后面可以跟很多参数,这里主要说明 -i -t参数。
只用 -i 时,由于没有分配伪终端。所以界面没有 Linux 命令提示符,但命令结果仍然可以返回。当 -i -t 一起使用时,则可以看到 Linux 命令提示符。

3.2.5 导出容器

docker export 容器ID > 导出文件名.格式
docker export fee3c9b69a60 > ubuntu.zip
docker export fee3c9b69a60 > ubuntu.tar

3.2.6 导入容器

导出文件:cat 文件名称 | docker import - 镜像用户/镜像名:镜像版本
如:cat ubuntu.zip | docker import - ricky.ubuntu:1.0

也可以通过制定 URL 或者某个目录来导入
docker import http://study.163.com/image.tgz example/imagerepo

3.2.7 删除容器

删除一个终止的容器:docker container rm 容器
如:docker container rm ubuntu:16.04

如果要删除一个运行中的容器,可以使用参数 -f。Docker 会发送 SIGKILL 信号给容器。
如:docker container rm -f ubuntu:16.04

删除所有终止状态的容器:docker container prune

4. 构建私有镜像

4.1 Dockerfile与指令

如果想深入了解的话,可以查看官方文档,这里对 Dockerfile 和指令做简单的描述

4.1.1 Dockerfile

Dockerfile 是什么
镜像的构建实际上是指定每一层所添加的配置、文件,我们使用命令来修改、安装、构建、操作每一层镜像,Dockerfile 中就包含了这些命令,也就是说 Dockerfile 是用来构建镜像的脚本。

使用 Dockerfile
我们可以使用docker build命令从Dockerfile和上下文来构建镜像,上下文是指一组位于指定PATHURL的文件,PATH指的是本地目录,URL指的是 Git 仓库的地址。

docker build .

使用这个命令可以使用当前目录下的 Dockerfile 来构建镜像

注意:不要使用根目录/作为 PATH 路径

4.1.2 指令

4.1.2.1 FROM:指定基础镜像

格式:FROM 镜像
指定一个镜像为基础镜像,在其上进行定制。基础镜像是必须指定的,所以 FROM 是必备的指令,并且必须是第一条指令。

Docker 存在一个特殊的镜像名为 scratch,这是个虚拟的概念,表示一个空白的镜像FROM scratch,如果为此为基础镜像的话,意味着不已任何镜像为基础,接下来的制定将作为第一层的开始。

对于 Linux 下静态编译的程序来说,并不需要有操作系统提供运行时支持。所需的一切库都已经在可执行文件里了,所以 FROM scratch 会让镜像体积更加小巧。

4.1.1.2 RUN:执行命令

有两种格式
shell 格式:RUN <命令>
如:RUN echo hello > 123.txt
exec 格式:RUN 可执行文件 参数...
如:RUN make -C /user/src/redis install

4.1.1.3 COPY:复制文件

格式:COPY 源路径... 目标路径

COPY 指令将从构建上下文目录中 源路径 的文件/目录,复制到新的一层的镜像内的 目标路径 位置。如:COPY package.json /user/src/app/

源路径可以是多个,甚至可以是通配符,如:
COPY hom* /mydir/
COPY hom?.txt /mydir/

4.1.1.4 ADD:更高级的复制

ADD 指令和 COPY 的格式和性质基本一致,但是 ADD 添加了一些功能。如:源路径可以是一个 RUL,这种情况下,Docker 会试图去下载这个链接的文件放到目标路径中。

Docker 官方的 Dockerfile 最佳实践文档中,要求尽可能地使用 COPY。因为 COPY 的语义很明确,就是复制文件而已,而 ADD 包含了更复杂的功能,其行为也不一定很清晰。最适合使用 ADD 的场合,就是文件需要自动解压缩时。

因此所有的文件复制使用 COPY,尽在需要自动解压缩时使用 ADD。

4.1.1.5 CMD:启动容器

CMD 指令的格式和 RUN 相似,也是两种格式:

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

Docker 不是虚拟机,容器就是进程。既然是进程,就需要在启动时指定运行的程序及参数,CMD 指令就是用于指定默认的容器主进程启动命令的。

4.1.1.6 ENTRYPOINT:入口点

ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数。ENTRYPOINT 在运行时也可以使用,不过比 CMD 要繁琐,需要通过 docker run 的参数 --entrypoint 来指定。

当指定了 ENTRYPOINT 后,CMD 的含义就发生了改变,不再是直接的运行其命令,而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令,它将变为:
ENTRYPOINT <CMD>

4.1.1.7 ENV:环境变量

格式有两种
ENV <key> <value>
ENV <key1>=<value1>...

后面的其他指和运行时的应用,都可以直接使用这里定义的环境变量。如:
ENV VERSION=1.0 DEBUG=on ...
$VERSION #使用环境变量

下列指令可以支持环境变量:ADD、COPY、ENV、EXPOSE、LABEL、WORKDIR、VOLUME、STOPSIGNAL、ONBUILD

4.1.1.8 ARG:构建参数

格式:ARG <key1>=<value1>...
ARG 和 ENV 都是设置环境变量,不同的是,ARG 所设置的环境变量只能在构建时使用,将来容器运行时是不存在这些环境变量的。但不要因此就是用 ARG 保存密码之类的信息,因为 docker history 还是可以看到所有值的。

该指令的值可以在 docker build 中使用 --build-arg <key>=<value> 来覆盖。

4.1.1.9 VOLUME:定义匿名卷

格式:VOLUME <路径>...

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

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

在运行时也可以覆盖挂载配置:docker run -d -v mydata:/data xxx

上述命令使用 mydata 这个命名卷挂载到了 /data 这个位置,替代了 Dockerfile 中的匿名卷配置。

4.1.1.10 ESPOSE:声明端口

EXPOSE <端口1> <端口2>...

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

在 Dockerfile 中写入这样的声明有两个好处:

  1. 帮助镜像使用者理解这个镜像服务的守护端口,以便配置映射
  2. 运行时使用随机端口映射时(docker run -P),会自动映射 EXPOST 的端口

4.1.1.11 WORKDIR:指定工作目录

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

使用 WORKDIR 指令来指定当前的工作目录,以后各层的当前目录就被改为指定的目录,如果该目录不存在,则会帮你建立目录。

Dockerfile 不能等同于 shell 脚本,比如:

RUN cd /app
RUN echo "hello" > hello.txt

上述 Dockerfile 构建后,会发现找不到 /app/hello.txt 文件,在 shell 中,连续两个命令在同一个进程执行,因此前一个命令修改的内存状态,会直接影响到后一个命令;但在 Dockerfile 中,这两个 RUN 命令的执行环境根本不同,是两个完全不同的容器。这是不了解 Dockerfile 构建分层存储时会导致的错误:
每一个 RUN 都是启动一个容器、执行命令、然后提交存储层文件变更。

4.1.1.12 USER:指定当前用户

USER <用户名>
USER 指令将切换用户,并影响之后的层,这个用户必须是事先建立好的,也可以通过 RUN 来建立用户。

RUN groupadd -r redis && useradd -r -g redis redis
USER redis
RUN ["redis-server"]

4.1.1.13 HEALTHCHECK:健康检查

HEALTHCHECK [选项] CMD <命令>

HEALTHCHECK 指令通过判断容器主进程的服务状态是否还正常,来反应容器的实际状态。

指定了 HEALTHCHECK 之后,启动容器,初始状态为 starting,在执行健康检查成功后变为 healthy,如果连续一定次数失败,则变为 unhealthy。
HEALTHCHECK 支持一下选项
--interval=<间隔>:两次健康检查的间隔,默认30秒
--timeout=<时长>:健康检查命令运行超时时间,如果超时,则本次检查被视为失败,默认30秒
--retries=<次数>:当连续失败指定次数后,容器状态视为 unhealthy,默认3次

健康状态命令的输出(包括 stdout 和 stderr)都会被存储于健康状态了,可以用 docker inspect查看

HEALTHCHECK NONE可以屏蔽掉基础镜像的健康检查指令

4.1.1.14 ONBUILD:作为基础镜像时的指令

ONBUILD 后面跟的是其他的指令,这些指令在当前构建时不会被执行,只有以当前镜像,去构建下一级镜像时才会被执行。

4.2 制作和使用本地镜像

Docker 提供了 docker save 和 docker load 命令,用于将镜像保存为一个 tar 文件,然后传输到另一个位置上,在加载进来。这是在没有 Docker Registry 时的做法,现在已经不推荐,镜像迁移用改直接使用 Docker Registry,无论是 Docker Hub 还是内网搭建私有 Registry 都可以。

保存 nginx 镜像:docker save nginx | gzip > nginx-latest/tar/gz
然后复制到另一台机器上
加载镜像:docker load -i nginx-latest.tar.gz

4.3 Docker 运行 spring boot 程序

参考spring boot 官网文档
创建一个 maven 工程,添加 spring-boot-starter-web 依赖和 maven 插件

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.1.7.RELEASE</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>2.1.7.RELEASE</version>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

添加一个 test 接口

@RestController
@RequestMapping("docker")
public class TestController {
    @GetMapping("test")
    public Object test() {
        return "test msg";
    }
}

添加启动方法

@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

访问一下看看 http://127.0.0.1:8080/docker/test

访问成功,打包然后上传至安装 docker 的服务器
编写 Dockerfile:

# 使用 openjdk8作为基础镜像
FROM openjdk:8-jdk-alpine
# 声明存储卷
VOLUME /tmp
# 复制测试用的 jar
ARG JAR_FILE=docker-test.jar
COPY ${JAR_FILE} app.jar
# 启动
ENTRYPOINT ["java","-jar","/app.jar"]

构建镜像docker build .

[root@localhost ~]# docker build .
Sending build context to Docker daemon  19.97kB
Step 1/5 : FROM openjdk:8-jdk-alpine
8-jdk-alpine: Pulling from library/openjdk
e7c96db7181b: Downloading [==================================>                ]  1.893MB/2.757MB
f910a506b6cb: Pulling fs layer 
c2274a1a0e27: Downloading 
8-jdk-alpine: Pulling from library/openjdk
e7c96db7181b: Pull complete 
f910a506b6cb: Pull complete 
c2274a1a0e27: Pull complete 
Digest: sha256:94792824df2df33402f201713f932b58cb9de94a0cd524164a0f2283343547b3
Status: Downloaded newer image for openjdk:8-jdk-alpine
 ---> a3562aa0b991
Step 2/5 : VOLUME /tmp
 ---> Running in 674e7b49f36d
Removing intermediate container 674e7b49f36d
 ---> 98ff1119d9b5
Step 3/5 : ARG JAR_FILE=docker-test.jar
 ---> Running in 7b229ac4733f
Removing intermediate container 7b229ac4733f
 ---> 69a9ef473207
Step 4/5 : COPY ${JAR_FILE} app.jar
 ---> 4b52b1faccf5
Step 5/5 : ENTRYPOINT ["java","-jar","/app.jar"]
 ---> Running in c9279dfc6757
Removing intermediate container c9279dfc6757
 ---> 2f62070f51a1
Successfully built 2f62070f51a1

构建成功,启动:docker run -it -p 8080:8080 --rm 2f62070f51a1
访问一下看看,能出结构就代表成功: http://IP:8080/docker/test

5. 私有仓库

5.1 安装

拉取并运行私有仓库
docker run --name registry -d -p 5000:5000 --restart=always -v /opt/data/registry:/var/lib/registry registry

docker 默认只支持 HTTPS 推送镜像,下面通过配置取消这个限制,否则只有本机可以推送镜像
vi /etc/docker/daemon.json
在原配置中添加

"insecure-registries":[
        "192.168.0.200:5000"
]

5.2 测试

利用 4.3 中生成的镜像测试私有仓库,刚刚构建时没有指定名称和标签,所以先改个名称和标签,注意这里一定要用 IP:端口 作为前缀
docker tag 2f62070f51a1 127.0.0.1:5000/docker-test:latest

[root@localhost ~]# docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
127.0.0.1:5000/docker-test         latest              2f62070f51a1        24 minutes ago      122MB
ubuntu              16.04               5e13f8dd4c1a        2 weeks ago         120MB
openjdk             8-jdk-alpine        a3562aa0b991        3 months ago        105MB
registry            latest              f32a97de94e1        5 months ago        25.8M

查看一下似有仓库的镜像:curl 127.0.0.1:5000/v2/_catalog

[root@localhost ~]# curl 127.0.0.1:5000/v2/_catalog
{"repositories":["docker-test"]}

删除 127.0.0.1:5000/docker-test :docker rmi 127.0.0.1:5000/docker-test,此时镜像应该已被删除

然后从私有仓库拉取:docker pull 127.0.0.1:5000/docker-test:latest,此时拉取了刚刚的镜像

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容