暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Docker 容器介绍

一、Docker简介

Docker 是一个开源项目,诞生于 2013 年初,最初是 dotCloud 公司内部的一个业余项目。它基于 Google 公司推出的 Go 语言实现。 项目后来加入了 Linux 基金会,遵从了 Apache 2.0 协议,项目代码在 GitHub 上进行维护。

Docker 项目的目标是实现轻量级的操作系统虚拟化解决方案。 Docker 的基础是 Linux 容器(LXC:Linux Container)等技术。

1.1、LXC与Docker的关系

  • Docker并不是LXC的替代品,Docker的底层就是使用了LXC来实现的。LXC将Linux进程沙盒化,使得进程之间相互隔离,并且能够控制各进程的资源分配。

  • 在LXC的基础之上,Docker提供了一系列更强的功能。

1.2、与虚拟机比较的优缺点

虚拟机也是一种虚拟化技术,它与 Docker 最大的区别在于它是通过模拟硬件,并在硬件上安装操作系统来实现。后续也会写关于虚拟化的文章。

Docker优点:
1)启动速度

  • 启动虚拟机需要先启动虚拟机的操作系统,再启动应用,这个过程非常

  • 启动 Docker 相当于启动宿主操作系统上的一个进程,速度很,秒级。

2)占用资源

  • 虚拟机是一个完整的操作系统,需要占用大量的磁盘、内存和 CPU 资源,一台机器只能开启几十个的虚拟机。

  • 而 Docker 只是一个进程,只需要将应用以及相关的组件打包,在运行时占用很少的资源,一台机器可以开启成千上万个 Docker。

3)跨平台可移植性

  • 虚拟机移植性差,跨平台性也很差,很多场景下不可跨平台;而docker只需要将容器打包成镜像,传到仓库,在另外的机器下载,生成容器就可以运行了,极快,极方便,而且还跨平台,只要机器上装了docker就可以运行了。

Docker的不足:

  • docker是基于Linux64 bit的,无法在32bit的 Linux/Windows/unix环境下使用

  • 隔离性相比KVM之类的虚拟化方案还是有些欠缺,不够彻底,所有container公用一部分的运行库

  • 资源隔离方面不如虚拟机,docker是利用cgroup实现资源限制的,只能限制资源消耗的最大值,而不能隔绝其他程序占用自己的资源

  • 网络管理相对简单,主要是基于namespace隔离

  • 安全性问题。docker目前并不能分辨具体执行指令的用户,只要一个用户拥有执行docker的权限,那么他就可以对docker的容器进行所有操作,不管该容器是否是由该用户创建。比如A和B都拥有执行docker的权限,由于docker的server端并不会具体判断docker cline是由哪个用户发起的,A可以删除B创建的容器,存在一定的安全风险。

二、基础配置&Centos8环境安装Docker

这里只讲Centos8环境安装docker,其它环境可以自行百度,安装很简单。
2.1、设置yum源——镜像仓库
官方yum源,贼慢

# 安装yum-config-manager配置工具
yum -y install yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

建议使用阿里云yum源:(推荐)

yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

2.2、安装

# 安装docker-ce版本
$ sudo yum install -y docker-ce
# 启动
$ sudo systemctl start docker
# 开机自启
$ sudo systemctl enable docker
# 查看版本号
$ sudo docker --version
# 查看版本具体信息
$ sudo docker version


docker-ce:docker CE是社区版本,现在改名叫moby了。

2.3、Docker镜像源设置

修改文件 /etc/docker/daemon.json,没有这个文件就创建
添加以下内容后,重启docker服务:

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

$ systemctl restart docker
$ systemctl status docker

注意:就是daemon.json文件中采用tab缩进,不能通过空格缩进,要不然重启会出现以下报错:

其他源地址:

# Docker 官方中国区

https://registry.docker-cn.com

# 网易

http://hub-mirror.c.163.com

# 中国科技大学

https://docker.mirrors.ustc.edu.cn

# 阿里云,需要自己用户的you_id

https://{you_id}.mirror.aliyuncs.com
# 以下是我自己的
https://ghtayq84.mirror.aliyuncs.com

查看阿里云自己的you_id
阿里云官网:https://www.aliyun.com/

第一步:登录之后选择控制台,找到容器镜像服务

第二步:查找镜像加速地址

三、镜像与容器基础

3.1、查看docker 帮助(docker --help)

Commands:
attach Attach to a running container # 当前 shell 下 attach 连接指定运行镜像
build Build an image from a Dockerfile # 通过 Dockerfile 定制镜像
commit Create a new image from a container's changes # 提交当前容器为新的镜像
cp Copy files/folders from the containers filesystem to the host path # 从容器中拷贝指定文件或者目录到宿主机中
create Create a new container # 创建一个新的容器,同 run,但不启动容器
diff Inspect changes on a container'
s filesystem # 查看 docker 容器变化
events Get real time events from the server # 从 docker 服务获取容器实时事件
exec Run a command in an existing container # 在已存在的容器上运行命令
export Stream the contents of a container as a tar archive # 导出容器的内容流作为一个 tar 归档文件[对应 import ]
history Show the history of an image # 展示一个镜像形成历史
images List images # 列出系统当前镜像
import Create a new filesystem image from the contents of a tarball # 从tar包中的内容创建一个新的文件系统映像[对应 export]
info Display system-wide information # 显示系统相关信息
inspect Return low-level information on a container # 查看容器详细信息
kill Kill a running container # kill 指定 docker 容器
load Load an image from a tar archive # 从一个 tar 包中加载一个镜像[对应 save]
login Register or Login to the docker registry server # 注册或者登陆一个 docker 源服务器
logout Log out from a Docker registry server # 从当前 Docker registry 退出
logs Fetch the logs of a container # 输出当前容器日志信息
port Lookup the public-facing port which is NAT-ed to PRIVATE_PORT # 查看映射端口对应的容器内部源端口
pause Pause all processes within a container # 暂停容器
ps List containers # 列出容器列表
pull Pull an image or a repository from the docker registry server # 从docker镜像源服务器拉取指定镜像或者库镜像
push Push an image or a repository to the docker registry server # 推送指定镜像或者库镜像至docker源服务器
restart Restart a running container # 重启运行的容器
rm Remove one or more containers # 移除一个或者多个容器
rmi Remove one or more images # 移除一个或多个镜像[无容器使用该镜像才可删除,否则需删除相关容器才可继续或 -f 强制删除]
run Run a command in a new container # 创建一个新的容器并运行一个命令
save Save an image to a tar archive # 保存一个镜像为一个 tar 包[对应 load]
search Search for an image on the Docker Hub # 在 docker hub 中搜索镜像
start Start a stopped containers # 启动容器
stop Stop a running containers # 停止容器
tag Tag an image into a repository # 给源中镜像打标签
top Lookup the running processes of a container # 查看容器中运行的进程信息
unpause Unpause a paused container # 取消暂停容器
version Show the docker version information # 查看 docker 版本号
wait Block until a container stops, then print its exit code # 截取容器停止时的退出状态值

3.2、镜像(Image)简介

Docker镜像就是一个Linux的文件系统(Root FileSystem),这个文件系统里面包含可以运行在Linux内核的程序以及相应的数据。

1)谈到这里,先补充一点与Linux操作系统相关的知识:

  • 一般而言, Linux分为两个部分:Linux内核(Linux Kernel)与用户空间,而真正的Linux操作系统,是指Linux内核,我们常用的Ubuntu、CentOS等操作系统其实是不同厂商在Linux内核基础上添加自己的软件与工具集(tools)形成的发布版本(Linux Distribution)。

  • 因此,我们也可以把镜像看成是上面所说的用户空间,当Docker通过镜像创建一个容器时,就是将镜像在定义好的用户空间作为独立隔离的进程运行在宿主机的Linux内核之上

2)这里要强调一下镜像的两个特征:

  • 镜像是分层(Layer)的:即一个镜像可以多个中间层组成,多个镜像可以共享同一中间层,我们也可以通过在镜像添加多一层来生成一个新的镜像

  • 镜像是只读的(read-only):镜像在构建完成之后,便不可以再修改,而上面我们所说的添加一层构建新的镜像,这中间实际是通过创建一个临时的容器,在容器上增加或删除文件,从而形成新的镜像,因为容器是可以动态改变的

3) Docker镜像与Linux的关系图:

3.3、镜像简单使用

Docker中与镜像操作相关的命令都在docker image这条子命令下,通过docker image --help这条命令,可以看到镜像相关的详细文档,如下:

[root@centos8-nat-168-182-152 ~]# docker image --help

Usage: docker image COMMAND

Manage images

Commands:
build Build an image from a Dockerfile # 构建镜像的命令
history Show the history of an image # 显示镜像构建历史过程
import Import the contents from a tarball to create a filesystem image # 导入一个由容器导出的镜像
inspect Display detailed information on one or more images # 显示一个镜像的详细信息
load Load an image from a tar archive or STDIN # 从一个文件或标准输入流中导入镜像
ls List images # 查看镜像列表
prune Remove unused images # 删除虚悬镜像
pull Pull an image or a repository from a registry # 从仓库拉取镜像
push Push an image or a repository to a registry # 推送镜像到仓库
rm Remove one or more images # 删除镜像
save Save one or more images to a tar archive (streamed to STDOUT by default) # 保存镜像到文件
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE # 给镜像打标签

Run 'docker image COMMAND --help' for more information on a command.

1)获取镜像

docker image pull [OPTIONS] NAME[:TAG|@DIGEST]

当然,docker image pull有更简洁的用法:如:

docker pull [OPTIONS] NAME[:TAG|@DIGEST]

【示例】要拉取镜像,需要指定Docker Registry的URL和端口号,默认是Docker Hub,因为Docker Hub很慢,所以我们上面设置了国内的加速地址,拉取镜像没有指定版本的话,就是拉取最新版latest

$ docker pull centos
# 查看
$ docker image ls
# 查看镜像的简介写法
$ docker images


2)docker tag 用于给镜像打标签,语法如下:

docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]

【示例】我对 centos 进行开发,开发了第一个版本,我就可以对这个版本打标签,打完标签后会生成新的镜像:

$ docker tag centos "centos:v1"
$ docker image ls


3)镜像导出与导入
如果想与别人共享某个镜像,除了从镜像服务仓库中pull镜像和把镜像push到仓库上去之外,其实我们还可以将本地构建好的镜像直接导出并保存为文件发送给别人,如下将centos:v1打包:

$ docker image save centos:v1 -o centos-v1.tar

再另外的机器上导入镜像

$ docker image load < centos-v1.tar
#等价
$ docker image load -i centos-v1.tar


4)删除本地镜像

要删除一个或多个本地的镜像,可以使用下面的命令:

docker image rm [option] IMAGE1,IMAGE2,...IMAGEn

也可以使用更简洁的方式,如:

docker rmi [option] IMAGE1,IMAGE2,...IMAGEn

4.1)可以使用镜像的长ID、镜像短ID、镜像摘要以及镜像名称来删除镜像,如下:

$ docker image rm 300e315adb2f

一般更常用镜像的短ID,如:

$ docker image rm 300e3

简短格式

# 强制删除-f
$ docker rmi -f 300e315adb2f

4.2)当然也可以通过镜像名称,不带版本就是删除latest版本

$ docker image rm centos:v1


4.3)清除本地全部镜像,慎用

$ docker image rm $(docker images -qa)

4.4)另外,一般如果镜像已经被使用来创建容器,使用上面的命令删除会报下面的错误,告诉我们该镜像已经被使用,不允许删除。

Error response from daemon: conflict: unable to remove repository reference "mysql:5.7" (must force) - container ccd406c07a78 is using its referenced image e1e1680ac726

对于已经被用于创建容器的镜像,删除方法有两种,一种是先把容器删除,再删除镜像,另一种则只需要在删除镜像的命令中跟一个-f参数便可,如:

$ docker rim -f 300e315adb2f

3.4、容器(Container)

容器与镜像的关系,就如同面向编程中对象与类之间的关系。一层读写层+多层只读层

因为容器是通过镜像来创建的,所以必须先有镜像才能创建容器,而生成的容器是一个独立于宿主机的隔离进程,并且有属于容器自己的网络和命名空间。

镜像由多个中间层(layer)组成,生成的镜像是只读的,但容器却是可读可写的,这是因为容器是在镜像上面添一层读写层(writer/read layer)来实现的,如下图所示:

Docker中与容器操作相关的命令都在docker container这条子命令下,通过docker container --help这条命令,可以看到容器相关的详细文档,如下:

[root@centos8-nat-168-182-152 ~]# docker container --help

Commands:
attach Attach local standard input, output, and error streams to a running container # 当前 shell 下 attach 连接指定运行镜像
commit Create a new image from a container's changes # 提交当前容器为新的镜像
cp Copy files/folders between a container and the local filesystem # 从容器中拷贝指定文件或者目录到宿主机中
create Create a new container # 创建一个新的容器,同 run,但不启动容器
diff Inspect changes to files or directories on a container'
s filesystem # 查看 docker 容器变化
exec Run a command in a running container # 在已存在的容器上运行命令
export Export a container's filesystem as a tar archive # 导出容器的内容流作为一个 tar 归档文件[对应 import ]
inspect Display detailed information on one or more containers # 查看容器详细信息
kill Kill one or more running containers # kill 指定 docker 容器
logs Fetch the logs of a container # 输出当前容器日志信息
ls List containers # 查看在跑容器列表
pause Pause all processes within one or more containers # 暂停容器
port List port mappings or a specific mapping for the container # 列出端口映射
prune Remove all stopped containers # 移除所有停止的容器
rename Rename a container # 容器改名
restart Restart one or more containers # 重启容器
rm Remove one or more containers # 删除容器
run Run a command in a new container # 创建一个新的容器并运行一个命令
start Start one or more stopped containers # 启动容器
stats Display a live stream of container(s) resource usage statistics # 列出容器资源使用情况
stop Stop one or more running containers # 停止容器
top Display the running processes of a container # 查看容器中运行的进程信息
unpause Unpause all processes within one or more containers # 取消暂停容器
update Update configuration of one or more containers # 更新容器配置
wait Block until one or more containers stop, then print their exit codes # 截取容器停止时的退出状态值

容器常用选项:

-i, –interactive #交互式

-t, –tty #分配一个伪终端

-d, –detach #运行容器到后台

-e, –env #设置环境变量

-p, –publish list #发布容器端口到主机

–name string #指定容器名称

-h, –hostname #设置容器主机名

–restart string #容器退出时重启策略 默认no,可选值:[always|on-failure]

示例:
1)启动容器
启动容器有几种不同的方式,最常用的方法是使用docker run命令可以通过镜像创建一个容器,如:

# bin/bash表示运行容器后要执行的命令,会进入到容器,退出容器就停止了
$ docker run -it centos bin/bash
# 查看在跑的容器,因为退出了,所以查不到
$ docker container ls
# 简写
$ docker ps
# 查看所有容器,包括停止的容器-a
$ docker container ls -a


2)docker run命令有一些比较常用的参数,比如容器是一种提供服务的守护进程,那么通常需要开放端口供外部访问,如果镜像本地不存在,会先去远程仓库拉取,再启动容器,如:

$ docker run -p 80:80 nginx

也可以为容器指定一个名称,如:

$ docker run -p 80:80 --name webserver nginx


另外一种则是使用docker start命令重新启动已经停止运行的容器,如:

# container_id表示容器的id,container_name表示容器名称
$ docker start [container_id|container_name]
$ docker start webserver


而对于正在运行的容器,也可以通过docker restart命令重新启动。

$ docker restart webserver

3)有时候,只想查到容器的ID【-q】,可以用下面的命令:

$ docker ps -aq

4)停止容器

$ docker stop webserver

批量停止容器,如:

$ docker stop $(docker ps -qa)

5)删除容器

# 可以通过container_id或container_name删除
$ docker container rm webserver
# 简写格式,container省略
$ docker rm 0736b2f43143

删除掉所有已退出的container,-f:filter(过滤),去掉过滤就是删除所有在跑容器,如果加-a就是删除所有的容器。

$ docker container prune
# 与上面等价
$ docker rm $(docker container ls -f "status=exited" -q)
$ docker rm $(docker container ls -q)
$ docker rm $(docker ps -a -q)

以上方式只能删除停止的容器的,如果想通过上面的方式删除在跑的容器会报错,如下:

Error response from daemon: You cannot remove a running container 5d3a84b4b89bd39f85eced22aa2ccba425089c92a6827494abd767878fe60ded. Stop the container before attempting removal or force remove

# 加-f强制删除
$ docker rm -f webserver

3.5、容器的三种运行模式

第一种运行模式:运行后退出
下面语句创建的容器,在运行后会退出:

$ docker run centos echo "hellowrold"

第二种运行模式:常驻内存,就是守护进程的模式(-d)
如果容器中运行一个守护进程,则容器会一直处于运行状态,如:

$ docker run -d -p 80:80 nginx


第三种运行模式:交互式
我们也可以在运行容器时,直接与容器交互,退出容器就停止了。

$ docker run -it centos bin/bash


3.6、进入docker容器的两种方式

1)使用docker attach进入Docker容器

docker attach可以attach到一个已经运行的容器,然后进行命令执行的动作。退出会导致容器的停止

# 创建一个容器,在后台跑
$ docker run -itd ubuntu:14.04 bin/bash
# 查看ID
$ docker ps
$ docker attach 90aad27b52a4

但在,使用该命令有一个问题。当多个窗口同时使用该命令进入该容器时,所有的窗口都会同步显示。如果有一个窗口阻塞了,那么其他窗口也无法再进行操作。因为这个原因,所以docker attach命令不太适合于生产环境
2)使用docker exec进入Docker容器(推荐)

对于正在运行的容器,我们也可以通过docker exec命令再次进入容器,退出不会导致容器停止,如:

$ docker exec -it 0d0355196eab bin/bash

当然还可以SSH进入Docker容器,但是对于容器来讲还是用docker exec比较多。
3.6、导出容器为镜像

$ docker export 90aad27b52a4 -o ./ubuntu-v1.tar.gz

将容器导出后,在另外一台有安装Docker的电脑中将文件包导入成为镜像,如:

docker import ubuntu-v1.tar.gz

四、制作镜像

4.1、基于容器制作
第一步:运行一个容器

$ docker run --name b1 -itd busybox

第二步:将容器制作成镜像
格式:

docker commit -m '镜像描述' -a '制作者' 容器名 镜像名

第三步:将制作好的镜像打成 tar 包
格式:

docker save -o tar包的名字 镜像名

$ docker  save  -o busybox-v1.tar.gz busybox-v1

第四步:将打包好的镜像,导入到其它机器上

$ docker image load < busybox-v1.tar.gz
#等价
$ docker image load -i busybox-v1.tar.gz

可以通过scp传到其它机器上去,也可以传到docker仓库,docker仓库下面会将。
4.2、build方式——Dockerfile创建镜像
使用Dockerfile是更推荐的方式,这样可以让使用者更清晰地看到这个镜像的制作细节,逻辑清晰,便于管理
1)Docketfile指令
FROM

FROM就是指定基础镜像,因此在DockerFile中,FROM是必备指定,并且必需是第一条指令!格式为:

FROM <image>

FROM <image>:<tag>

除了指定现有的基础镜像以外,DockerFile还存在一个特殊的镜像srcatch,这个镜像是一个虚拟的概念,并不实际存在,它表示一个空白的镜像

FROM scratch

MAINTAINER<name>

指定镜像的作者信息,包含镜像的所有者和联系信息

RUN

RUN指令是用来执行命令行命令的,由于命令行的强大功能,RUN指令是定制镜像时最常用的指令之一,格式为:

#shell格式:就像在命令行中输入的Shell脚本命令一样,比如之前的:
RUN <command> (shell模式)
#exec格式:像是函数调用的格式
RUN ["executable file","param1","param2"] (exec模式)

COPY

COPY指令将从上下文目录中的指定路径下的文件或文件夹复制到新的一层的镜像内的指定路径之下,格式为:

COPY <源路径> ... <目标路径>

原路径可以是多个,甚至是通配符,其通配规则只需要满足GO语言的filepath.Math规则即可。
目标路径是容器内的绝对路径,也可以是工作目录下的相对路径,工作目录可以使用WORKDIR指令进行指定。

ADD

ADD指令和COPY的格式和性质基本一致,只不过是在COPY的基础上增加了一些功能。例如ADD指定中,源路径可以是一个远程URL,Docker引擎会自动帮我们将远程URL的文件下载下来到目标路径下,例如:

ADD http://192.168.182.130:8080/test.py test/

如果源路径是本地的一个tar压缩文件时,ADD指定在复制到目录路径下会自动将其进行解压,如下:

ADD docker2.tar test/

压缩格式为gzip、bzip2以及xz的情况下,ADD指令都会将其解压缩!
注意:

目标路径为一个URL时,会将其自动下载到目标路径下,但是其权限被自动设置成了600,还得增加一层RUN命令进行更改权限,还不如指定只用一层RUN,所以ADD命令并不实用,并不推荐使用

CMD

CMD指令与RUN指令相似,也具有两种格式:

CMD ["executable file","param1","param2"] (exec模式)
CMD command param1 param2 (shell模式)

之前介绍容器的时候就说过,Docker不是虚拟机,容器就是进程。既然是进程,那么在启动容器的时候,就需要指定运行的程序及参数。CMD就是指定默认的容器主进程的启动命令的
示例:

FROM ubuntu
CMD echo "Hello Docker!"

值得注意的是,如果使用shell格式,那么实际的命令会被包装成为sh -c的参数的形式进行执行。上面的CMD指令,在实际执行中会变成:

CMD ["sh", "-c", "echo", "Hello Docker!"]

因为这种特性,一些命令在加上sh -c之后,有可能会发生意想不到的错误,因此在Dockerfile中使用RUN指令时,更加推荐使用exec格式!最后需要牢记,使用docker run命令指定要执行的命令可以覆盖RUN指令,如果我们的docker run中指定了我们将要执行的命令,并且在Dockerfile中也指定了CMD命令,那么最终只会执行docker run命令中指定的命令。比如有这样一个Dockerfile:

FROM ubuntu
CMD ["echo", "Hello Docker!"]

ENTRYPOINT

ENTRYPOINT指令和CMD指令目的一样,都是指定容器运行程序及参数,并且与CMD一样拥有两种格式的写法:

ENTRYPOINT ["executable file","param1","param2"] (exec模式)
ENTRYPOINT command param1 param2 (shell模式)

与CMD指令一样,ENTRYPOINT也更加推荐使用exec格式,ENTRYPOINT在docker run命令中同样也可以进行指定,只不过比CMD指令来的繁琐一些,需要指定--entrypoint参数。同样,在docker run命令中指定了--entrypoint参数的话,会覆盖Dockerfile中ENTRYPOINT上的指令

当指定了ENTRYPOINT指令时,CMD指令里的命令性质将会发生改变!CMD指令中的内容将会以参数形式传递给ENTRYPOINT指令中的命令,如下:

FROM ubuntu
ENTRYPOINT ["rm", "docker2"]
CMD ["-rf"]

其实,它真正执行的命令将会是:

rm docker2 -rf

ENV

ENV指令用于设置环境变量,格式有两种:
ENV
ENV = = …

这个指令非常简单,就是用于设置环境变量而已,无论是接下来的指令,还是在容器中运行的程序,都可以使用这里定义的环境变量。例如:

FROM ubuntu:16.04
ENV MODE=test

ARG

构建参数ARG和ENV指令一样,都是设置环境变量。与之不同的是,ARG设置的环境变量只是在镜像构建时所设置的,在将来容器运行时是不会存在这些环境变量的。与ENV指令的使用类似,如下:

FROM ubuntu:16.04
ARG app="python-pip"
RUN apt-get update && apt-get install -y $app && rm -rf var/lib/apt/lists/*

VOLUME

VOLUME指令用于构建镜像时定义匿名卷,通过 VOLUME 指令创建的挂载点,无法指定主机上对应的目录,是自动生成的。其格式有两种:

VOLUME <路径>
VOLUME [“<路径1>”, “<路径2>”, …]

之前我们说过,容器存储层应该保持无状态化,容器运行时应尽量保持容器内不发生任何写入操作,对于需要保存动态数据的应用,其数据文件应该将其保存在数据卷中(VOLUME)
定义一个匿名卷:

FROM ubuntu:16.04
VOLUME data

定义多个匿名卷:

FROM ubuntu:16.04
VOLUME ["/data", "/command"]

EXPOSE <port> [<port>...]

暴露容器端口
要将 EXPOSE 和在运行时使用 -p <宿主端口>:<容器端口> 区分开来。-p:是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射,所以作用不大。

WORKDIR

使用WORKDIR指令来制定工作目录(或者称为当前目录),以后各层操作的当前目录就是为指定的目录,如果该目录不存在,WORKDIR会自动帮你创建目录,如下:

FROM ubuntu:16.04
WORKDIR data/test
RUN mkdir docker && echo "test" > demo.txt

WORKDIR指令可以通过docker run命令中的-w参数来进行覆盖

USER
USER指令用于将会用以什么样的用户去运行,例如:

FROM ubuntu:16.04
USER docker

USER指令可以在docker run命令中的-u参数进行覆盖

HEALTHCHECK

HEALTHECHECK指令是告诉Docker该如何判断容器的状态是否正常,这是1.12引入的新指令,其格式有两种:

HEALTHCHECK [options] CMD <命令>:检查容器健康状态的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,这一行将会屏蔽掉其健康检查指令

HEALTHECHECK支持下列选项:

  • –interval=<间隔>:两次检查的时间间隔,默认为30s

  • –timeout=<时长>:健康检查命令运行超时时间,如果超过这个时间,本次健康检查将会判定为失败,默认为30s

  • –retries=<次数>:当连续失败指定次数之后,则将容器状态视为unhealthy,默认为3次

在没有HEALTHCHECK指令之前,Docker引擎只可以通过容器内主进程是否退出来判断容器状态是否异常。很多情况下这没有问题,但是如果程序进入了死锁状态,或者死循环状态,应用进程并不退出,但是该容器已经无法继续提供服务了。在1.12之前,Docker引擎不会检测到容器的这种状态,从而不会重新调度,导致可能容器已经无法提供服务了却仍然还在接收用户的请求

假设我们有个镜像是最简单的Web服务,我们希望增加健康检查来判断Web服务是否在正常工作,我们可以用curl来帮助判断,其Dockerfile的HEALTHCHECK可以这么写:

FROM nginx
RUN apt-get update && apt-get install -y curl && rm -rf var/lib/apt/lists/*
HEALTHCHECK --interval=5s --timeout=3s CMD curl -fs http://localhost/ || exit 1

CMD、NETRYPOINT一样,HEALTHCHECK指令只可以出现一次,如果有多个HEALTHCHECK指令,那么只有最后一个才会生效!!!

ONBUILD

ONBUILD是一个特殊的指令,它后面跟着的是其他指令,比如COPY、RUN等,而这些命令在当前镜像被构建时,并不会被执行。只有以当前镜像为基础镜像去构建下一级镜像时,才会被执行。格式为:ONBUILD <其他指令>

Dockerfile中的其他指令都是为了构建当前镜像准备的,只有ONBUILD指令是为了帮助别人定制而准备的。例如:

from ubuntu:16.04
WORKDIR data
ONBUILD RUN mkdir test

创建镜像(注:-t 表示为该镜像起名称,另外,构建命令后面有个英文实心点,表示当前目录。)

$ docker build -t test01 .

此时,我们以此Dockerfile进行构建镜像ubuntu:test,并以此镜像为基础创建并启动一个容器,进入容器后,容器会自动切换到WORKDIR指令下的目录,此时我们使用ls命令会发现在工作目录下,并未创建test文件夹

此时,我们再创建一个Dockerfile,只需一个FROM指令即可,使其继承刚刚我们构建的ubuntu:test镜像,如下:

FROM test01


LABEL

LABEL指令可以为镜像指定标签,其格式为:LABEL <key1>=<value1> <key2>=<value2> ...

LABEL后面是键值对,多个键值对以空格进行隔开,如果value中包含空格,请使用""将value进行圈起来,如下:

FROM ubuntu:16.04
LABEL name=test
LABEL description="a container is used to test"

我们知道,DockerFile的每一个指令都会新构建一层,所以,上面的LABEL我们可以写成一条指令,用空格进行隔开,如下:

FROM ubuntu:16.04
LABEL name=test description="a container is used to test"


2)综合示例
Dockerfile

FROM centos
MAINTAINER liugp<2920992033@qq.com>

#把宿主机当前的上下文的c.txt拷贝到容器的/usr/local路径下
COPY c.txt usr/local/cincontainer.txt
#把java与tomcat添加到容器中
ADD jdk-10.0.2_linux-x64_bin.tar.gz usr/local/
ADD apache-tomcat-9.0.11.tar.gz usr/local/
#安装vim编辑器
RUN yum -y install vim
#设置工作访问的时候的WORKDIR,登录落脚点
ENV MYPATH usr/local
WORKDIR $MYPATH
#配置java与tomcat环境变量
ENV JAVA_HOME usr/local/jdk-10.0.2
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINE_HOME usr/local/apache-tomcat-9.0.11
ENV CATALINE_BASE usr/local/apache-tomcat-9.0.11
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINE_HOME/lib:$CATALINE_HOME/bin
#容器运行时监听的端口
EXPOSE 8080
#启动时运行tomcat
# ENTRYPOINT ["/usr/local/apache-tomcat-9.0.11/bin/startup.sh"]
# CMD ["/usr/local/apache-tomcat-9.0.11/bin/startup.sh","run"]
CMD usr/local/apache-tomcat-9.0.11/bin/startup.sh && tail -f usr/local/apache-tomcat-9.0.11/bin/logs/catalina.out

创建镜像(注:-t 表示为该镜像起名称)

# docker build -t liugptomcat9 .
# docker run -d -p 9080:8080 --name myt9 -v Users/liugp/mydocker/tomcat9/test:/usr/local/apache-tomcat-9.0.11/webapps/test -v Users/liugp/mydocker/tomcat9/tomcat9logs/:/usr/local/apache-tomcat-9.0.11/webapps/logs --privileged=true liugptomcat9

#mysql
docker run -p 12345:3306 --name mysql -v Users/liugp/mydocker/mysql/conf:/etc/mysql/conf.d -v Users/liugp/mydocker/mysql/logs:/logs -v Users/liugp/mydocker/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.6

#redis
docker run -p 6379:6379 -v Users/liugp/mydocker/myredis/data:/data -v Users/liugp/mydocker/myredis/conf/redis.conf:/usr/local/etc/redis/redis.conf -d redis:3.2 redis-server usr/local/etc/redis/redis.conf --appendonly yes

五、搭建Docker私有仓库(Repository)

简介

在 Docker 中,当我们执行 docker pull xxx 的时候 ,默认它实际上是从 registry.hub.docker.com 这个地址去查找,这就是Docker公司为我们提供的公共仓库。在工作中,我们不可能把企业项目push到公有仓库进行管理。所以为了更好的管理镜像,Docker不仅提供了一个中央仓库,同时也允许我们搭建本地私有仓库。

5.1、registry 的搭建

Docker 官方提供了一个搭建私有仓库的镜像 registry ,只需把镜像下载下来,运行容器并暴露5000端口,就可以使用了。

docker run -d -v opt/registry:/var/lib/registry -p 5000:5000 --restart=always --name myregistry registry

  • --restart=always:docker重启会自动启动这个容器服务

  • Registry服务默认会将上传的镜像保存在容器的/var/lib/registry,我们将主机的/opt/registry目录挂载到该目录,即可实现将镜像保存到主机的/opt/registry目录了。

$ docker pull busybox
$ docker tag busybox localhost:5000/my-busybox
$ docker push localhost:5000/my-busybox

如果出现如下错误,请把selinux关闭试试,我这里就是把selinux关闭了就ok了。

查看仓库

$ curl http://localhost:5000/v2/_catalog
或者
$ curl http://192.168.182.130:5000/v2/_catalog


【验证】删除本地的镜像,再拉取仓库的镜像

$ docker image rm localhost:5000/my-busybox

从本地registry中拉取 localhost:5000/my-ubuntu 镜像:

$ docker pull localhost:5000/my-busybox


但是这种registry只是本地能使用,我们找另外一台主机192.168.182.152往该registry中push镜像:

这是因为从docker1.13.2版本开始,使用registry时,必须使用TLS保证其安全。
搭建外部可访问的Registry(192.168.182.130)

使用TLS认证registry容器时,必须有证书。一般情况下,是要去认证机构购买签名证书。这里使用openssl生成自签名的证书

1)生成自签名证书

$ mkdir -p /opt/docker/registry/certs
$ openssl req -newkey rsa:4096 -nodes -sha256 -keyout /opt/docker/registry/certs/domain.key -x509 -days 365 -out /opt/docker/registry/certs/domain.crt


2)创建带有TLS认证的registry容器

ocker run -d --name registry2 -p 5000:5000 -v /opt/docker/registry/certs:/certs -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key registry


3)在每一个docker客户端宿主机,添加域名映射和创建对应的目录。

$ echo '192.168.182.130 registry.docker.com' >> /etc/hosts
$ mkdir -p /etc/docker/certs.d/registry.docker.com:5000

4)将证书 domain.crt 复制到每一个docker客户端宿主机/etc/docker/certs.d/registry.docker.com:5000/ca.crt,不需要重启docker,这里域名就是生成秘钥填写的

$scp -p /opt/docker/registry/certs/domain.crt root@192.168.182.152:/etc/docker/certs.d/myregistry.docker.com\:5000/ca.crt

5)push镜像到registry

# 下载一个镜像
$ docker pull hello-world
# 打标签
$ docker tag hello-world registry.docker.com:5000/hello-world
# push到远程仓库
docker push registry.docker.com:5000/hello-world


6)列出私有仓库中的所有镜像

# -k:允许curl使用非安全的ssl连接并且传输数据(证书不受信)
$ curl -X GET https://registry.docker.com:5000/v2/_catalog -k


文章转载自大数据与云原生技术分享,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论