在我们开始使用docker之前,我们先把私服搭建起来,这种顺序通常适用于生产级或实际工作的时使用docker的习惯。我们遵循这样的习惯。

概念

当我们执行docker pusll xxx的时候,默认是从docker公共仓库下载镜像到本地,当我们执行docker push xxx的时候,默认是推送到docker公共仓库中,docker 公共仓库地址:

https://hub.docker.com/ 如果想了解的话自行登录注册账号,就可以使用了。

在企业生产级运维中,一般不会随意把公司应用镜像推送到公共仓库中,所以我们需要搭建自己内部的仓库,我们本章就是讲解如何搭建自己的私服。其实笔者认为docker社区版搭建私服的过程还是蛮繁杂的,不过只要读者跟着笔者一步步操作,搭建自己的私服完全不在话下。话不多说,我们直接在创建的虚拟机节点2上进行如下步骤:

安装私服

我们选择在node2机子上安装docker私服。安装步骤如下:

1、卸载docker,主要是检查之前是否安装过,有安装的话把老的卸载掉

 

yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

2、安装docker

yum install -y yum-utils \
  device-mapper-persistent-data \
  lvm2
yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo

3、配置镜像下载加速

vi /etc/docker/daemon.json

输入以下内容:

{
  "registry-mirrors": ["https://registry.docker-cn.com"]
}

docker安装后默认没有daemon.json这个配置文件,需要进行手动创建。配置文件的默认路径:/etc/docker/daemon.json

该文件作为 Docker Engine 的配置管理文件, 里面几乎涵盖了所有 docker 命令行启动可以配置的参数。

更多配置可参考官方文档说明:

https://docs.docker.com/engine/reference/commandline/dockerd/#/configuration-reloading

 

4、启动docker

systemctl start docker

5、下载、运行私服镜像:

docker run -d -p 5000:5000 --restart=always --name registry registry:2

--restart=always意思是只要该容器没有启动,总是尝试重启。

6、查看运行容器列表

docker container ls或docker ps

 

7、浏览器访问:

http://node2:5000/v2/_catalog 出现{}则表示成功。

笔者这里为了方便,直接停掉防火墙服务:

systemctl stop firewalld

推送镜像到私服

1、拉ubuntu:16.04镜像

docker pull ubuntu:16.04

2、将镜像标记为localhost:5000/my-ubuntu。这会为现有镜像创建一个附加标记。当标记的的第一部分是主机名和端口时,Docker在推送时将其解释为注册表的位置。例如localhost:5000/my-ubuntu中的localhost:5000代表该镜像推送到localhost:5000私服。格式是固定的。官方约定俗成的。

docker images

创建新的镜像,镜像命名前缀指定了推送的私服地址

docker image tag ubuntu:16.04 localhost:5000/myfirstimage

 

3、将镜像推送到运行于的本地注册表localhost:5000:

 docker push localhost:5000/myfirstimage

如果你的私服是在其它机子且非https协议的,push会报错:

http: server gave HTTP response to HTTPS client

你需要在daemon.json配置文件中配置:--insecure-registry如下:

{
  "insecure-registries": ["ip:port"],
  "registry-mirrors": ["https://registry.docker-cn.com"]
}

4、删除本地镜像

docker image remove ubuntu:16.04 或docker rmi ubuntu:16.04
docker image remove localhost:5000/myfirstimage

5、再从本地私服拉下来

dockder images
docker pull localhost:5000/myfirstimage

6、访问私服地址

http://node2:5000/v2/_catalog

可以看到我们刚才推送的镜像

 

7、停止注册表。

 8、删除容器

docker container rm -v registry

 

下面我们重启启动私服,并将容器内部镜像的存储路径映射到宿主机外面:

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

 

-v 选项参数指定将容器内部路径映射到宿主机某个路径,上面命令我们将私服的镜像存在位置到宿主机/var/docker/registry下

测试下载镜像:

docker pull ubuntu:16.04
docker image tag ubuntu:16.04 localhost:5000/myfirstimage
docker push localhost:5000/myfirstimage
cd /var/docker/registry

就可以看到镜像被推送到该目录下,上面我们简单了解了docker私服的使用,搭建起了简单私服,为我们后面实战使用。

 

更多关于docker私服信息请查看官方文档:

https://docs.docker.com/registry/deploying/

docker知识库地址:https://docs.docker.com/glossary/?term=repository

docker私服安全性

不知读者是否发现,我们私服实在太不安全了,我们直接在浏览器回车就能看到所有的镜像列表,如果公司是内网,虽然至少对外是安全的,但始终对内部还是有可能会暴露我们应用存储的信息,如果是在AWS或阿里云等其他公网上部署,那就更加不安全了,我们开发的应用可能随时被外人发现并pull下来看个遍。对,实际上我们需要设置安全登录账号和密码,这样才稍微放心些,除了配置登录密码外,我们还要保证网络传输过程的安全,所以还要配置tls传输加密。

这里有个细节问题就是当我们配置好tls之后,访问的协议会从http变为https,除此之外,我们push进行时标签前缀以域名替代之前的localhost或ip,上面我们提过的配置项(insecure-registries)可以删除且不会报错。

注:tls是ssl标准的实现,两者之间意思大致相同。事实上我们现在用的都是TLS,但因为历史上习惯了SSL这个称呼平常很多开发同事还是以称呼SSL为多。后面笔者描述TLS或SSL时是同一个意思,不做区分。

话不多说,下面给出私服配置tls传输加密以及配置登录密码步骤:

1、申请个人或公司域名,笔者已经在腾讯云申请好了域名laizhiy.cn

这个很多人都会觉得麻烦,还要花钱去买个域名?哎不学了,放弃了。笔者这里给你打个气,域名不贵,一年才几十块钱。去万网或腾讯云买个吧,其它地方说不定还用得上,如果确实不想买也没关系,就直接跳过这章,不会影响后面的学习哈。

2、解析一个二级域名(registry.laizhiy.cn)到node2的ip上

我们私服是部署到虚拟化的节点2(node2)上的

3、在本地电脑ping registry.laizhiy.cn测试是否解析成功

4、申请ssl证书,笔者这里选择免费ssl证书,有效期一年

阿里云或腾讯云申请免费ssl证书,具体方式可自行查阅网络资料,该文档是针对docker的,其它知识避免过多讲解,知识是讲不完的,我们要抓重点。

5、下载申请通过的证书文件 (分别后缀为.key和.crt两个文件)

笔者文件名为:1_registry.laizhiy.cn_bundle.crt 和 2_registry.laizhiy.cn.key

6、开通node2 443端口防火墙

7、创建目录mkdir -p /opt/etc/docker/registry/ssl/cert

8、将.key和.crt两个文件上传到 /opt/etc/docker/registry/ssl/cert目录下

文件上传下载可以使用lrzsz  yum install lrzsz

9、停止运行中的注册表docker stop registry(这里假定你的容器名字为registry)

10、重新启动注册表

docker run -d --rm --name registry \ 
-v  /opt/etc/docker/registry/ssl/certs/:/certs \ 
-v /var/docker/registry:/var/lib/registry \
 -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
 -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/1_registry.laizhiy.cn_bundle.crt \
 -e REGISTRY_HTTP_TLS_KEY=/certs/2_registry.laizhiy.cn.key \
 -p 443:443 registry:2

另外说明下,当同一台服务器安装多个应用且端口发生冲突时,可以通过nginx代理到registry。有兴趣的读者可自行查阅网络资料。

 

11、查看镜像列表

curl https://registry.laizhiy.cn/v2/_catalog 或浏览器访问:

https://registry.laizhiy.cn/v2/_catalog

能够看到我们之前上传的镜像就证明SSL配置成功了

 

 

12、测试使用域名进行上传镜像到私服

docker pull hello-world
docker images
docker tag hello-world registry.laizhiy.cn/hello-world:1.0
docker images
docker push registry.laizhiy.cn/hello-world:1.0

curl https://registry.laizhiy.cn/v2/_catalog

 

 

上面演示完了配置SSL的过程,下面我们继续配置密码,步骤如下:

13、创建目录mkdir -p /opt/etc/docker/registry/auth

14、通过docker自带的htpasswd工具生成用户名为:lazy密码:123456文件

docker run --rm --entrypoint htpasswd \
 registry:2 -Bbn lazy 123456 > /opt/etc/docker/registry/auth/htpasswd

15、停止私服docker stop registry

16、重启docker registry

docker run -d --rm --name registry  \
-v /opt/etc/docker/registry/ssl/certs/:/certs  \
-v /var/docker/registry:/var/lib/registry \
-v /opt/etc/docker/registry/auth:/auth  \
-e "REGISTRY_AUTH=htpasswd"  \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm"  \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd  \
-e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
 -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/1_registry.laizhiy.cn_bundle.crt \
 -e REGISTRY_HTTP_TLS_KEY=/certs/2_registry.laizhiy.cn.key \
 -p 443:443 registry:2

17、验证密码有效性

浏览器直接访问:https://registry.laizhiy.cn/v2/_catalog,此时,会弹出登录框,输入lazy 123456即可,或输入读者自己定义的用户名和密码。

docker tag hello-world registry.laizhiy.cn/hello-world:1.1
docker push registry.laizhiy.cn/hello-world:1.1

 

咋整,现在连基本的push都失败了,没关系,我们下面通过命令行进行登录,其实这才是我们要的效果,安全性得到了保证。

18、登录私服

docker login registry.laizhiy.cn
docker push registry.laizhiy.cn/hello-world:1.1

 

19、登出私服

有登录自然有登出,命令如下:

docker logout registry.laizhiy.cn

20、补充说明:

读者可能很快发现个问题,就是要运行一个私服太不容易了,光命令行就这么长,其实官方还提供了通过配置文件的方式进行配置,后面在集成ui时笔者会演示一下配置文件的使用方式,这里先给出配置文件的官方文档位置: https://docs.docker.com/registry/configuration/

github上还提供了配置文件起步配置:

https://github.com/docker/distribution/blob/master/cmd/registry/config-example.yml

假定你的配置文件为/opt/etc/docker/registry.yml,配置完成后我们只需要这样启动容器就行了:

docker run -d -p 5000:5000 --name registry \ 
-v /opt/etc/docker/registry.yml:/etc/docker/registry/config.yml \
registry:2

另外,我们这里用到了-v -e -p这些选项命令,这里暂时简单讲解下含义:

-v :将容器某个目录或文件绑定/映射到宿主机某个目录或文件上

-v /opt/etc/docker/registry/ssl/certs/:/certs代表将容器的/certs目录绑定到宿主机的/opt/etc/docker/registry/ssl/certs这个目录,从Docker 17.06开始,(这里提一下,本篇教程是基于docker18.09版本的)。对于数据绑定或挂载大部分使用--mount方式,更加灵活,关于docker数据管理后面会有专门的章节来讲解。

-e: 通用配置项一般都用-e,大致意思是配置某个变量为什么值,给到docker本身程序使用

-p:将容器内的某个端口绑定到宿主机某个端口。这里涉及到docker网络相关的知识,笔者在后面章节会单独提取出来讲解,这里提前跟读者打个招呼,网络这一块对于学习docker来说至关重要。

-d:以守护进程方式在后台运行,相反前台运行命令为: -t -i

--rm:容器退出时,删除容器,如果容器比较稳定,建议不加--rm,下次直接docker start 容器ID/容器名称即可,方便很多。

21、告一段落

OK,至此,私服安全性已经得到正常的保障,接下来我们还要继续完善私服,想要搭好一个安全且好用的私服,真可谓千里迢迢啊,没办法,谁让咱们用的是社区版的呢,企业版的docker私服就没那么多麻烦事了,不过麻烦也好,可以多学习动手能力和解决问题的耐心,不但省钱还能学习东西,哈哈。

 

docker私服ui

从上面我们看到,官方社区版的私服毫无界面可言,直接返回json结果,下面我们继续在上面的基础上搭建一个带ui界面的docker私服,开源github地址为:https://github.com/mkuchin/docker-registry-web,这里多说一句,目前开源的docker registry ui项目有多个,详细有哪些读者可以自行查阅网络资料,都是非docker 官方开源的,我们这里选择的是docker-registry-web

玩docker无非就是知道大概原理,懂得敲命令,命令如下:

1、下载镜像

docker pull hyper/docker-registry-web

1、启动私服

启动ui容器之前需要先启动实际的私服,按上面启动命令启动私服:

docker run -d --rm --name registry  \
 -v /opt/etc/docker/registry/ssl/certs/:/certs  \
 -v /var/docker/registry:/var/lib/registry -v /opt/etc/docker/registry/auth:/auth  \
-e "REGISTRY_AUTH=htpasswd"  \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm"  \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd  \
-e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
 -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/1_registry.laizhiy.cn_bundle.crt \
 -e REGISTRY_HTTP_TLS_KEY=/certs/2_registry.laizhiy.cn.key \
 -p 443:443 registry:2

2、启动ui

docker run -d -p 8080:8080 \
--rm --name registry-web  \
-e REGISTRY_URL=https://registry.laizhiy.cn/v2 \
-e REGISTRY_NAME=localhost:5000 \
-e REGISTRY_TRUST_ANY_SSL=true \
-e REGISTRY_BASIC_AUTH="bGF6eToxMjM0NTY="  \
hyper/docker-registry-web

这里着重讲解下下面两个配置含义:

-e REGISTRY_TRUST_ANY_SSL=true : 注册表使用了可信任的任何ssl证书

-e REGISTRY_BASIC_AUTH="bGF6eToxMjM0NTY="  :用户名:密码经过base64编码后的值,这里笔者直接从浏览器登录私服后的请求报文header auth baisc中复制过来

启动后浏览器直接访问:http://node2:8080/ 或http://registry.laizhiy.cn:8080/

 

OK, 我们终于有个简单的ui界面可以看到我们的镜像列表了。但是,还不够,因为这个ui界面只能查看,当然对应这个不用登录直接就可以进去的web ui来说,只能查询可以保证镜像的安全,但是有时候我们自己想通过ui删除镜像时就显得力不从心了,所以,接下来我们继续完善这个ui,使之支持删除功能,但可以想象,支持删除功能的ui一定是需要登录密码的。

我们这里将兑现上面对读者的承诺,使用配置文件进行配置,而不是使用命令行。但是笔者不会给出每一项配置的含义,请读者自行翻阅官方文档:

https://docs.docker.com/registry/configuration/

话不多说,步骤如下:

1、创建注册表配置文件/opt/etc/docker/registry/conf/registry.yml,内容如下:

 

version: 0.1
storage:
  filesystem:
    rootdirectory: /var/lib/registry
 
http:
  addr: 0.0.0.0:443
  tls:
    certificate: /certs/1_registry.laizhiy.cn_bundle.crt
    key: /certs/2_registry.laizhiy.cn.key
 
auth:
  token:
    realm: http://registry.laizhiy.cn:8080/api/auth
    service: https://registry.laizhiy.cn
    issuer: lazy
    rootcertbundle: /etc/docker/registry/auth.cert
log:
  level: info

上面配置需要注意的是我们将注册表从密码htpasswd方式转为token鉴权auth的方式,这种方式更适合应用之间的安全访问控制。auth和htpasswd只能使用其中一种。

2、重启启动私服

docker stop registry

docker run -d --rm --name registry-srv  \
-v /opt/etc/docker/registry/ssl/certs/:/certs  \
-v /opt/etc/docker/registry/conf/registry.yml:/etc/docker/registry/config.yml:ro \
-v /var/docker/registry:/var/lib/registry  \
-v /opt/etc/docker/registry/ssl/certs/1_registry.laizhiy.cn_bundle.crt:/etc/docker/registry/auth.cert:ro  \
-p 443:443 registry:2

 

注意了,这里有坑,就是容器名称不能为registry,随便改一个,这里笔者改为registry-srv。这是个很细节的坑,务必注意。

3、创建注册表ui配置文件/opt/etc/docker/registry/conf/registry-web.yml,内容如下:

registry:

url: https://registry.laizhiy.cn/v2  
  name: https://registry.laizhiy.cn
  readonly: false
  trust_any_ssl: true
  
  auth:
    enabled: true
    issuer: 'lazy'
    key: /conf/auth.key
  log:
    level: info

4、重启注册表ui

docker stop registry-web

docker run -d -p 8080:8080 \
--rm --name registry-web  \
-v /opt/etc/docker/registry/conf/registry-web.yml:/conf/config.yml:ro \
-v /var/docker/registry-web:/data \
-v /opt/etc/docker/registry/ssl/certs/2_registry.laizhiy.cn.key:/conf/auth.key:ro  \
hyper/docker-registry-web

5、浏览器访问:http://registry.laizhiy.cn:8080/

 

输入admin admin登录进去后,可以查看到我们之前推送上去的镜像。ui是搭起来了,后面教下大家怎么用。

1、admin账号是默认账号,该账号角色不要去操作它

2、创建一个账号,比如笔者这里为:账号:lazy 密码:lazy

3、按需分配角色给账号,笔者这里直接分配所有角色给账号lazy

4、登出admin账号,登入lazy账号测试是否可以登录

5、回到节点2服务器执行如下命令:

docker images
docker tag hello-world registry.laizhiy.cn/hello-world:1.2
docker push registry.laizhiy.cn/hello-world:1.2

提示没有权限,我们登录一下,登录用户名和密码是多少呢?没错,是ui创建的用户lazy或admin,我们知道admin没有只有后台ui_admin角色,这个角色是不能push的,因为我们没有分配对应权限的角色给admin,当然我们可以分配权限给admin但强烈不建议这么做。

我们先用admin登录然后push,看是否跟我们预期一样,没有推送权限。

可以看到admin是没有push权限的,现在我们登出admin,然后再登录lazy,再push

 

OK,至此,我们完成了docke私服接近生产级的搭建,是否有感受到笔者前面说的繁杂了吗?

当然还可以继续完善,比如通过命令docker create network xxx自定义网络、通过swarm集群方式部署、通过docker-compose在单个服务器或集群中批量部署所有相关的服务等等。这些知识后面笔者会将一一讲解。不过,目前的部署方式已经基本满足生产级部署。

想要深入学好任何一门技术,都是这样,任重而道远。当然也有很多技术人是蜻蜓点水,通过某些博客直接复制跑起来就完事,这种方式适合入门时的快速体验,不能做到熟练使用。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐