Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。 说dockerfile之前我们先说一下dockercommit
注意: docker commit 命令除了学习之外,还有一些特殊的应用场合,比如被入侵后保存现 场等。但是,不要使用 docker commit 定制镜像,定制镜像应该使用 Dockerfile 来完成 镜像是容器的基础,每次执行 docker run 的时候都会指定哪个镜像作为容器运行的基础。 我们之前所使用的镜像都是docker hub等网站上的,直接使用这些镜像可以满足一定的需求,而当这些镜像无法直接满足需求时候,我们需要定制这些镜像.之前有说过,镜像是多层存储,每一层是在前一层的基础上进行的修改,而容器也是多层存储,是在以镜像为基础层,在其基础上加一层作为容器运行时的存储层.
docker pull daocloud.io/library/nginx
docker run --name webserver -d -p 80:80 daocloud.io/library/nginx
# 我们访问这个web服务,会看到nginx的默认欢迎界面,假如我不喜欢这个界面,想看到欢迎docker的文字,可以exec
curl 119.3.255.91
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
docker exec -it webserver bash
root@6e63ab0d5109:/# echo '<h1>Hello,Docker!</h1>'> /usr/share/nginx/html/index.html
root@6e63ab0d5109:/# exit
exit
# 我们在访问时候就发现内容改变了
curl 119.3.255.91
<h1>Hello,Docker!</h1>
# 我们修改了容器的文件,就是改动了容器的存储层,我们可以通过docker diff命令看到具体变动
docker diff webserver
C /root
A /root/.bash_history
C /run
A /run/nginx.pid
C /var
C /var/cache
C /var/cache/nginx
A /var/cache/nginx/fastcgi_temp
A /var/cache/nginx/proxy_temp
A /var/cache/nginx/scgi_temp
A /var/cache/nginx/uwsgi_temp
A /var/cache/nginx/client_temp
C /usr
C /usr/share
C /usr/share/nginx
C /usr/share/nginx/html
C /usr/share/nginx/html/index.html
现在我们定制好了变化,我们希望将其保存下来形成镜像. 要知道,当我们运行一个容器的时候(如果不使用卷的话),我们做的任何文件修改都会被 记录于容器存储层里。而 Docker 提供了一个 docker commit 命令,可以将容器的存储层保 存下来成为镜像。换句话说,就是在原有镜像的基础上,再叠加上容器的存储层,并构成新 的镜像。以后我们运行这个新镜像的时候,就会拥有原有容器最后的文件变化(类似于虚拟机的快照)。
docker commit 的语法格式为:
docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]
# 我们可以用下面的命令将容器保存为镜像
docker commit -a="youmen <18621048481@163.com>" -m="edited nginx Default page" webserver nginx:v2
* -m 提交的描述信息
* -a 指定镜像作者
* webserver为你要给那个容器做成镜像的那个容器名字或者ID
* nginx:v2是形成的新镜像名
# 接下来我们基于这个创建好的新镜像再启动一个容器.
docker run --name web2 -d -p 81:80 nginx:v2
curl `cat ip.txt`:81
<h1>Hello,Docker!</h1>
# 就这样,我们完成了一次基于容器构建定制镜像的操作.
使用 docker commit 命令虽然可以比较直观的帮助理解镜像分层存储的概念,但是实际环境 中并不会这样使用。 首先,如果仔细观察之前的 docker diff webserver 的结果,你会发现除了真正想要修改的 /usr/share/nginx/html/index.html 文件外,由于命令的执行,还有很多文件被改动或添加 了。这还仅仅是最简单的操作,如果是安装软件包、编译构建,那会有大量的无关内容被添 加进来,如果不小心清理,将会导致镜像极为臃肿。 此外,使用 docker commit 意味着所有对镜像的操作都是黑箱操作,生成的镜像也被称为黑 箱镜像,换句话说,就是除了制作镜像的人知道执行过什么命令、怎么生成的镜像,别人根 本无从得知。而且,即使是这个制作镜像的人,过一段时间后也无法记清具体在操作的。虽 然 docker diff 或许可以告诉得到一些线索,但是远远不到可以确保生成一致镜像的地步。 这种黑箱镜像的维护工作是非常痛苦的。 而且,回顾之前提及的镜像所使用的分层存储的概念,除当前层外,之前的每一层都是不会 发生改变的,换句话说,任何修改的结果仅仅是在当前层进行标记、添加、修改,而不会改 动上一层。如果使用 docker commit 制作镜像,以及后期修改的话,每一次修改都会让镜像 更加臃肿一次,所删除的上一层的东西并不会丢失,会一直如影随形的跟着这个镜像,即使 根本无法访问到。这会让镜像更加臃肿.
从刚才的 docker commit 的学习中,我们可以了解到,镜像的定制实际上就是定制每一层所 添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚 本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问 题、体积的问题就都会解决。这个脚本就是 Dockerfile。 Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层, 因此每一条指令的内容,就是描述该层应当如何构建。 还以之前定制 nginx 镜像为例,这次我们使用 Dockerfile 来定制。 在一个空白目录中,建立一个文本文件,并命名为 Dockerfile :
cat DockerFile
mkdir mynginx
cd mynginx
vim Dockerfile
FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
FROM为指定基础镜像,我们定制镜像,肯定要以一个镜像为基础,在其上做定制,而FROM就是指定基础镜像,因此一个Dockerfile中FROM是必备的命令,并且必须是第一条指令. 在Docker Store上有非常多高质量的官方镜像,有可以直接拿来使用的服务类镜像,如nginx,redis,mysql,mongo,tomcat等,也有方便开发、构建、运行各种语言的镜像,如node,openjdk,python,ruby,golang等,可以在其中寻找一个最符合我们的镜像为基础镜像进行定制. 如果还没有找到对应服务的镜像,官方镜像中提供了一些更为基础的操作系统镜像,如ubuntu,debian,centos,fedora,alpine等,这些操作系统的软件库为我们提供了更广阔的扩展空间. 除了选择现有镜像为基础镜像外,Docker 还存在一个特殊的镜像,名为 scratch 。这个镜像 是虚拟的概念,并不实际存在,它表示一个空白的镜像。 如果你以 scratch 为基础镜像的话,意味着你不以任何镜像为基础,接下来所写的指令将作 为镜像第一层开始存在。 不以任何系统为基础,直接将可执行文件复制进镜像的做法并不罕见,比如 swarm 、 coreos/etcd 。对于 Linux 下静态编译的程序来说,并不需要有操作系统提供运行时 支持,所需的一切库都已经在可执行文件里了,因此直接 FROM scratch 会让镜像体积更加小 巧。使用 Go 语言 开发的应用很多会使用这种方式来制作镜像,这也是为什么有人认为 Go 是特别适合容器微服务架构的语言的原因之一。
RUN 指令是用来执行命令行命令的。由于命令行的强大能力, RUN 指令在定制镜像时是最 常用的指令之一。其格式有两种: shell 格式: RUN <命令> ,就像直接在命令行中输入的命令一样。刚才写的 Dockerfile 中 的 RUN 指令就是这种格式。
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
exec 格式: RUN ["可执行文件", "参数1", "参数2"] ,这更像是函数调用中的格式。 既然 RUN 就像 Shell 脚本一样可以执行命令,那么我们是否就可以像 Shell 脚本一样把每个 命令对应一个 RUN 呢?比如这样:
cat Dockerfile
FROM debian:jessie
RUN apt-get update
RUN apt-get install -y gcc libc6-dev make
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz"
RUN mkdir -p /usr/src/redis RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1
RUN make -C /usr/src/redis
RUN make -C /usr/src/redis install
之前说过,Dockerfile 中每一个指令都会建立一层, RUN 也不例外。每一个 RUN 的行为, 就和刚才我们手工建立镜像的过程一样:新建立一层,在其上执行这些命令,执行结束 后, commit 这一层的修改,构成新的镜像。 而上面的这种写法,创建了 7 层镜像。这是完全没有意义的,而且很多运行时不需要的东 西,都被装进了镜像里,比如编译环境、更新的软件包等等。结果就是产生非常臃肿、非常 多层的镜像,不仅仅增加了构建部署的时间,也很容易出错。 这是很多初学 Docker 的人常 犯的一个错误。 Union FS 是有最大层数限制的,比如 AUFS,曾经是最大不得超过 42 层,现在是不得超过 127 层。因此上面Dockerfile可以这样写:
cat DockerFile
FROM debian:jessie
RUN buildDeps='gcc libc6-dev make' \
&& apt-get update \ && apt-get install -y $buildDeps \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" \
&& mkdir -p /usr/src/redis \ && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
&& make -C /usr/src/redis \
&& make -C /usr/src/redis install \
&& rm -rf /var/lib/apt/lists/* \ && rm redis.tar.gz \
&& rm -r /usr/src/redis \
&& apt-get purge -y --auto-remove $buildDeps
首先,之前所有的命令只有一个目的,就是编译、安装 redis 可执行文件。因此没有必要建立 很多层,这只是一层的事情。因此,这里没有使用很多个 RUN 对一一对应不同的命令,而是 仅仅使用一个 RUN 指令,并使用 && 将各个所需命令串联起来。将之前的 7 层,简化为了 1 层。在撰写 Dockerfile 的时候,要经常提醒自己,这并不是在写 Shell 脚本,而是在定义每 一层该如何构建。 并且,这里为了格式化还进行了换行。Dockerfile 支持 Shell 类的行尾添加 \ 的命令换行方 式,以及行首 # 进行注释的格式。良好的格式,比如换行、缩进、注释等,会让维护、排障 更为容易,这是一个比较好的习惯。 此外,还可以看到这一组命令的最后添加了清理工作的命令,删除了为了编译构建所需要的 软件,清理了所有下载、展开的文件,并且还清理了 apt 缓存文件。这是很重要的一步,我 们之前说过,镜像是多层存储,每一层的东西并不会在下一层被删除,会一直跟随着镜像。 因此镜像构建时,一定要确保每一层只添加真正需要添加的东西,任何无关的东西都应该清 理掉。 很多人初学 Docker 制作出了很臃肿的镜像的原因之一,就是忘记了每一层构建的最后一定要 清理掉无关文件。
在之前Dockerfile文件所在目录执行
cat DockerFile
mkdir mynginx
cd mynginx
# 我们继续编辑一下DockerFile
vim DockerFile
FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
docker build -t nginx:v3 .
# 最后的.表示本文执行的上下文路径
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM nginx
---> 231d40e811cd
Step 2/2 : RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
---> Running in 3a439666c4da
Removing intermediate container 3a439666c4da
---> 78990dc4a6a6
Successfully built 78990dc4a6a6
Successfully tagged nginx:v3
从命令的输出结果中,我们可以清晰的看到镜像的构建过程。在 Step 2 中,如同我们之前 所说的那样, RUN 指令启动了一个容器231d40e811cd,执行了所要求的命令,并最后提交 了这一层 3a439666c4da ,随后删除了所用到的这个容器78990dc4a6a6。 docker build [选项] <上下文路径/URL/-> 构建成功后我们可以跟nginx:v2那样运行这个镜像,结果一样. 这只是默认行为,实际上 Dockerfile 的文件名并不要求必须为 Dockerfile ,而且并不要求 必须位于上下文目录中,比如可以用 -f ../Dockerfile.php 参数指定某个文件作为 Dockerfile
是指在docker构建镜像,有时候想要使用本机的文件(比如复制),docker build命令知道这个路径后,会将这个路径下所有内容打包. 由于 docker 的运行模式是 C/S。我们本机是 C,docker 引擎是 S。实际的构建过程是在 docker 引擎下完成的,所以这个时候无法用到我们本机的文件。这就需要把我们本机的指定目录下的文件一起打包提供给 docker 引擎使用。 如果未说明最后一个参数,那么默认上下文路径就是 Dockerfile 所在的位置。 注意:上下文路径下不要放无用的文件,因为会一起打包发送给 docker 引擎,如果文件过多会造成过程缓慢。
直接用git repo 进行构建
yum -y install git
docker build https://github.com/twang2218/gitlab-ce-zh.git:8.14 docker
build https://github.com/twang2218/gitlab-ce-zh.git\#:8.14
Sending build context to Docker daemon 2.048 kB Step 1 :
FROM gitlab/gitlab-ce:8.14.0-ce.0 8.14.0-ce.0:
Pulling from gitlab/gitlab-ce
这行命令指定了构建所需的Git repo,并且指定默认的master分支,构建目录为/8.14/,然后Docker就会自己去git clone这个项目,切换到指定分支,并进入到指定目录后开始构建.
用给定的tar压缩包构建
docker build http://server/context.tar.gz
# 如果所给出的 URL 不是个 Git repo,而是个 tar 压缩包,那么 Docker 引擎会下载这个包,
# 并自动解压缩,以其作为上下文,开始构建。
从标准输入中读取Dockerfile进行构建
docker build - < Dockerfile
or
cat Dockerfile | docker build -
如果标准输入传入的是文本文件,则将其视为 Dockerfile ,并开始构建。这种形式由于直接 从标准输入中读取 Dockerfile 的内容,它没有上下文,因此不可以像其他方法那样可以将本 地文件 COPY 进镜像之类的事情。
从标准输入中读取上下文压缩包进行构建
docker build - < context.tar.gz
# 如果发现标准输入的文件格式是gzip、bzip2、以及xz的话,将会使其为上下文压缩包,直接将其展开,
# 将里面视为上下文,并开始构建.
FROM:定制的镜像都是基于 FROM 的镜像,这里的 nginx 就是定制需要的基础镜像。后续的操作都是基于 nginx。 RUN:用于执行后面跟着的命令行命令。有以下俩种格式
shell格式
RUN <命令行命令>
# <命令行命令> 等同于,在终端操作的 shell 命令。
exec格式
RUN ["可执行文件", "参数1", "参数2"]
# 例如:
# RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline
注意: Dockerfile的指令是每执行一次都会在docker上新建一层,所以过多无意义的层,会造成镜像膨胀过大,上面提到过,可以用&&符号链接命令,这样执行后,只会创建一层镜像
# 格式:
# COPY <源路径>...<目标路径>
COPY ["<源路径1>",..."<目标路径>"]
# 和RUN指令一样,也有两种格式,一种类似于命令行,一种类似于函数调用.
COPY指令将从构建上下文目录中<源路径>的文件/目录复制到新的一层的镜像内的<目标路径> 位置,比如.
COPY package.json /usr/src/app/
# <源路径> 可以是多个,甚至可以是通配符,其通配符规则要满足Go的filepath.Match规则,如:
COPY hom* /mydir/
COPY hom?.txt /mydir/
# <目标路径> 可以是容器内的绝对路径,也可以是相对于工作目录的相对路径.工作目录可以 用 WORKDIR 指令来指定).
# 目标路径不需要事先创建,如果目录不存在会在复制文件前先行 创建缺失目录
# 此外,还需要注意一点,使用 COPY 指令,源文件的各种元数据都会保留。比如读、写、执 行权限、文件变更时间等.
# 这个特性对于镜像定制很有用。特别是构建相关文件都在使用 Git 进行管理的时候。
ADD 指令和 COPY 的使用格式一致(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下: ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。 ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。
类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。 注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。 格式:
CMD <shell 命令>
CMD ["<可执行文件或命令>","<param1>","<param2>",...]
CMD ["<param1>","<param2>",...] # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。 但是, 如果运行 docker run 时使用了 --entrypoint 选项,此选项的参数可当作要运行的程序覆盖 ENTRYPOINT 指令指定的程序。 优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。 注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。 格式:
ENTRYPOINT ["<executeable>","<param1>","<param2>",...]
可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,以下示例会提到。 示例: 假设已通过 Dockerfile 构建了 nginx:test 镜像:
FROM nginx
ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参
不传参运行
docker run nginx:test
# 容器内会默认运行以下命令,启动主进程
nginx -c etc/nginx/nginx.conf
传参运行
docker run nginx:test -c /etc/nginx/new.conf
# 容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)
设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。 格式:
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
以下示例设置 NODE_VERSION = 7.2.0 , 在后续的指令中可以通过 $NODE_VERSION 引用:
ENV NODE_VERSION 7.2.0
RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
&& curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"
构建参数,与 ENV 作用一至。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。 构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖。 格式:
ARG <参数名>[=<默认值>]
定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。 作用:
格式
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
# 在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。
仅仅只是声明端口。 作用:
格式:
EXPOSE <端口1> [<端口2>...]
指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。 docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。 格式:
WORKDIR <工作目录路径>
用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。 格式:
USER <用户名>[:<用户组>]
用于指定某个程序或者指令来监控 docker 容器服务的运行状态。 格式:
# HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
# HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
# HEALTHCHECK [选项] CMD <命令> : 这边 CMD 后面跟随的命令使用,可以参考 CMD 的用法。
用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这是执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。 格式
ONBUILD <其它指令>
仓库(Repository)是集中存放镜像的地方 一个容易混淆的概念是注册服务器( Registry )。实际上注册服务器是管理仓库的具体服务 器,每个服务器上可以有多个仓库,而每个仓库下面有多个镜像。从这方面来说,仓库可以 被认为是一个具体的项目或目录。例如对于仓库地址 dl.dockerpool.com/ubuntu 来 说, dl.dockerpool.com 是注册服务器地址, Ubuntu 是仓库名。 大部分时候,并不需要这两者的概念.
目前Docker官方维护了一个公共仓库Docker Hub,其中包括了数量超过15000的镜像,大部分需求都可以通过在Docker Hub中直接下载镜像来实现. 注册,可以直接在https://cloud.docker.com免费注册一个Docker Hub账号. 登陆 可以通过执行docker login 命令交互式的输入用户名及密码来完成命令行界面登陆Docker Hub。docker logout退出登陆.
可以通过docker search命令来查找官方仓库中的镜像,并利用docker pull命令将他下载到本地.
docker search centos
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
centos The official build of CentOS. 5717 [OK]
ansible/centos7-ansible Ansible on Centos7 126 [OK]
jdeathe/centos-ssh OpenSSH / Supervisor / EPEL/IUS/SCL Repos - … 114 [OK]
consol/centos-xfce-vnc Centos container with "headless" VNC session… 101 [OK]
可以看到返回了很多包含关键字的镜像,其中包括镜像名字、描述、收藏数(表示该镜像的受关注程度),是否官方创建、是否自动创建. 根据是否是官方提供,可将镜像资源分为两类. 一种是类似centos这样的镜像,被称为基础镜像或根镜像,这些基础镜像由Docker公司创建、验证、支持、提供。这样的镜像往往使用单个单词作为名字. 还有一种类型,比如tianon/centos镜像,他是由Docker的用户创建并维护的,往往带有用户名称前缀,可以通过前缀username/来指定某个用户提供的镜像,比如tianon用户. 另外,在查找的时候可以通过--filter=stars=N参数可以显示收藏数量为N以上的镜像.
用户可以在登陆后通过docker push命令将自己的镜像推送到Docker Hub。 以下命令的flyingdreams请替换为你的Docker账号用户名.
docker login # 登陆自己的账号
docker tag nginx:v2 flyingdreams/nginx:v2
docker push flyingdreams/nginx:v2
自动创建(Automated Builds)功能对于需要经常升级镜像内程序来说,十分方便. 有时候,用户创建了镜像,安装了某个软件,如果程序发布新版本则需要手动更新镜像. 而自动创建允许用户Docker Hub指定跟踪一个目标网站(目前支持GitHub或BitBucket)上的项目,一旦项目发生新的提交或者创建新的标签(tag),Docker Hub会自动构建镜像并推送到Docker Hub中.
要配置自动创建,包括如下的步骤:
# 1. 创建并登陆Docker Hub,以及目标网站:
# 2. 在目标网站中连接账户到Docker Hub;
# 3. 在Docker Hub中配置一个自动连接:
# 4. 选取一个目标网站中的项目(需要含Dockerfile)和分支
# 5. 指定Dockerfile的位置,并提交创建.
# 之后,可以在Docker Hub的自动创建页面中跟踪每次创建的状态.
有时候使用Docker Hub这样的公共仓库可能不安全,用户可以创建一个本地仓库供私人使用. 通过官方提供的私有仓库镜像
registry
来搭建私有仓库。通过 humpback 快速搭建轻量级的Docker容器云管理平台 此外还有像Harbor,rancher等私有仓库。
# 自定义存储位置$HOME,一般是root
docker run -d \
-p 5000:5000 \
--restart=always \
--name registry \
-v $HOME/_docker/registry:/var/lib/registry \
registry:2.6
# 从官方仓库拉去一个镜像
docker pull nginx
docker tag nginx:latest 47.92.24.137:5000/test_nginx:latest
# 在推送到的时候报错误,默认是使用`https`提交,这个搭建的默认使用的是 `http`,解决方法两个:
# 创建一个https映射
# 将仓库地址加入到不安全的仓库列表中
# 我们使用第二种方法,加入到不安全的仓库列表中,修改docker配置文件
# `vi /etc/docker/daemon.json` 添加 `insecure-registries`配置信息
docker push 47.92.24.137:5000/test_nginx:latest
The push refers to repository [47.92.24.137:5000/test_nginx]
Get https://47.92.24.137:5000/v2/: http: server gave HTTP response to HTTPS client
cat /etc/docker/daemon.json
{
"insecure-registries":[
"47.92.24.137:5000"
]
}
systemctl stop docker
systemctl daemon-reload
systemctl start docker
# 推送到私有仓库中
docker push 47.92.24.137:5000/test_nginx:latest
ls /root/_docker/registry/docker/registry/v2/repositories/test_nginx/
_layers _manifests _uploads
Harbor 可帮助用户迅速搭建企业级的 Registry 服务, 它提供了管理图形界面, 基于角色的访问控制 ( Role Based Access Control), 镜像远程复制 (同步), AD/LDAP 集成, 以及审计日志等企业用户需求的功能, 同时还原生支持中文, 深受中国用户的喜爱;
是
VMware
公司开源了企业级Registry
项目, 其的目标是帮助用户迅速搭建一个企业级的Docker registry
服务。 由于 Harbor 是基于 Docker Registry V2 版本,所以 docker 版本必须>=1.10.0
docker-compose>=1.6.0
下载最新版 Docker Compose curl -L "https://github.com/docker/compose/releases/download/1.22.0/docker-compose-
下载最新版Docker Harbor
wget https://github.com/goharbor/harbor/releases/download/v1.10.0-rc1/harbor-offline-installer-v1.10.0-rc1.tgz
# 对二进制文件应用可执行权限:
sudo chmod +x /usr/local/bin/docker-compose
# 测试是否安装成功
docker-compose --version
# 按照上面给的docker harbor地址,下载离线安装包
tar xvf harbor-offline-installer-v1.8.1.tgz -C /usr/local/
vim /usr/local/harbor/harbor.yml
hostname: 47.92.24.137
# 运行安装脚本
./install.sh
[Step 0]: checking installation environment ...
Note: docker version: 19.03.4
Note: docker-compose version: 1.22.0
[Step 1]: loading Harbor images ...
Loaded image: goharbor/harbor-core:v1.8.1
Loaded image: goharbor/harbor-registryctl:v1.8.1
Loaded image: goharbor/redis-photon:v1.8.1
Loaded image: goharbor/notary-server-photon:v0.6.1-v1.8.1
Loaded image: goharbor/chartmuseum-photon:v0.8.1-v1.8.1
Loaded image: goharbor/harbor-db:v1.8.1
Loaded image: goharbor/harbor-jobservice:v1.8.1
Loaded image: goharbor/nginx-photon:v1.8.1
Loaded image: goharbor/registry-photon:v2.7.1-patch-2819-v1.8.1
Loaded image: goharbor/harbor-migrator:v1.8.1
Loaded image: goharbor/prepare:v1.8.1
Loaded image: goharbor/harbor-portal:v1.8.1
Loaded image: goharbor/harbor-log:v1.8.1
Loaded image: goharbor/notary-signer-photon:v0.6.1-v1.8.1
Loaded image: goharbor/clair-photon:v2.0.8-v1.8.1
[Step 2]: preparing environment ...
prepare base dir is set to /usr/local/harbor
Generated configuration file: /config/log/logrotate.conf
Generated configuration file: /config/nginx/nginx.conf
Generated configuration file: /config/core/env
Generated configuration file: /config/core/app.conf
Generated configuration file: /config/registry/config.yml
Generated configuration file: /config/registryctl/env
Generated configuration file: /config/db/env
Generated configuration file: /config/jobservice/env
Generated configuration file: /config/jobservice/config.yml
Generated and saved secret to file: /secret/keys/secretkey
Generated certificate, key file:/secret/core/private_key.pem, cert file:/secret/registry/root.crt
Generated configuration file: /compose_location/docker-compose.yml
Clean up the input dir
[Step 3]: starting Harbor ...
✔ ----Harbor has been installed and started successfully.----
Now you should be able to visit the admin portal at http://47.92.24.137.
For more details, please visit https://github.com/goharbor/harbor
接下来我们可以直接浏览器访问配置文件定义的IP或者域名加端口
# 因为harbor默认端口是80,而大多数时候是不希望使用80端口,修改方法如下
# vim harbor.yml
# 找到port选项修改端口,然后执行./install 就会使用配置文件端口
# 还有一种情况就是更改已有harbor的配置
vim docker-compose.yml
dns_search: .
ports:
- 99:80
auth:
token:
issuer: harbor-token-issuer
realm: http://47.92.24.137:99/service/token
rootcertbundle: /etc/registry/root.crt
service: harbor-registry
docker-compose down -v
docker-compose up -d
为了体现出效果,建议使用非harbor的另一台机器
# 镜像推送
docker login 47.92.24.137:99 -u admin -p youmen
vim /etc/docker/daemon.jsonyml
{
"insecure-registries":["47.92.24.137"]
}
systemctl daemon-reload
systemctl restart docker
# 因为docker默认使用的是https协议,而搭建harbor是http提供服务的,
# 所以要配置可信任,或者强制docker login和docker push 走http的80端口,而不是443端口.
docker tag nginx:latest 47.92.24.137:99/library/nginx:latest
docker push 47.92.24.137:99/library/nginx:latest
yum -y install dnsmasq
mkdir -p /data/ssl && cd /data/ssl
vim harbor.cfg
hostname = harbor.youmen.com
ui_url_protocol = https
db_password = root123
harbor_admin_password = baiyongjie
ssl_cert = /usr/local/harbor/cert/harbor.youmen.com.crt
ssl_cert_key = /usr/local/harbor/cert/harbor.youmen.com.key
# grep -Ev '#|^$' harbor.yml
hostname: harbor.youmen.com # 本机外网IP或域名,该地址供用户通过UI进行访问,不要使用127.0.0.1
https: # 用户访问私仓时使用的协议,默认时http,配置成https
port: 443 # https使用的端口
certificate: /usr/local/harbor/cert/harbor.youmen.com.crt # 设置证书文件路径
private_key: /usr/local/harbor/cert/harbor.youmen.com.key # 设置证书密钥文件路径
harbor_admin_password: youmen # harbor的管理员账户密码
database:
password: root123 # 指定mysql数据库管理员密码
data_volume: /data # image存储目录
clair:
updaters_interval: 12
http_proxy:
https_proxy:
no_proxy: 127.0.0.1,localhost,core,registry
jobservice:
max_job_workers: 10
chart:
absolute_url: disabled
log:
level: info
rotate_count: 50
rotate_size: 200M
location: /var/log/harbor
_version: 1.8.0
生成harbor证书
mkdir /usr/local/harbor/cert/
cd /usr/local/harbor/cert/
#生成根证书
openssl req -newkey rsa:4096 -nodes -sha256 -keyout ca.key -x509 -days 3650 -out ca.crt -subj "/C=CN/L=Shanghai/O=harbor/CN=harbor-registry"
#生成一个证书签名, 设置访问域名为 harbor.baiyongjie.com
openssl req -newkey rsa:4096 -nodes -sha256 -keyout harbor.youmen.com.key -out server.csr -subj "/C=CN/L=Shanghai/O=harbor/CN=harbor.youmen.com"
#生成主机证书
openssl x509 -req -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out harbor.youmen.com.crt
# 接下来执行自动安装脚本即可.
添加本地解析到hosts
#echo "192.168.1.155 harbor.baiyongjie.com" >> /etc/hosts
#cd /usr/local/harbor
# ./install.sh
官方建议不要在Harbor上启用https,而是将Harbor放置到一个SLB的后边,配置SLB的端口转发进行访问,或者再装一个Nginx,进行Nginx的端口转发. 如果想做一个HA方案的话,可以按照如下方式构建一个(主从模式个人感觉很不靠谱 负载均衡同时还要承担检查的任务,而Redis用于数据的缓存和消息队列的实现,Mysql存储用户信息和仓库信息,云存储用来存储Docker镜像.