个人亲自录制全套DevOps系列实战教程 :手把手教你玩转DevOps全栈技术
概述/目标
私服我们很熟悉了,比如docker hub就是官方私服,而有些情况比如我们自建的镜像,不想往外传,就需要考虑内部搭建一个私有服务器来存放私有的镜像。
Harbor是一个比较成熟且图形界面功能比较完善,而nexus从2升级到3后,做了很大的更改,其中就包括可以作为docker镜像的私服。在这里我们两种私服都讲一下。本节先来看看Nexus3的搭建及原理。
目标:
搭建docker私服将应用在jenkins构建完docker镜像后,优先上传到私服,而后部署容器时从私服拉取,这样我们搭建微服务集群的效率就会很高。
在实际生产中,我们一般采用k8s(docker集群化),这样的话如果没有私服,那么假设有3台k8s集群,那么构建镜像的主机可能是任意一个或者是都参与,那么每个主机本地都存一分镜像就会太过冗余,而如果由首次构建镜像的主机上传到私服,而其他主机直接拉取就会很快,并且镜像都在私服也方便管理,更加安全和方便治理。
Docker的概念:
在docker的概念中,如果要登录私服,私服必须是https协议服务才能进行正常鉴权,当然docker没那么傻,并没有规定那么死,
只不过出于安全考虑他期望是https,当然如果你有从CA认证机构购买的证书,当然一定要使用https,这样直接配置证书,证书是可以正常验证的;
而如果你使用的是自签发证书或者只有http的仓库服务,那么docker允许你将仓库加入到信任列表,即需要将仓库配置到要连接仓库的docker服务对应的daemon.json
"insecure-registries":[
"10.10.1.199:9082", # 提交时的hosted仓库
"10.10.1.199:9083", # 拉取时用的group仓库
]
这样配置好后,即便是http仓库或是自签发证书的https都可以正常登录。
允许docker使用Nexus账号登录私服:
说到这里顺便也讲一下docker登录私服的账号,既然docker login到私服,那肯定是需要账号,
默认Nexus是不允许docker使用Nexus的管理账号登录的
需要管理员开启该功能:"设置"->"Security"->"Realms"->"Docker Bearer Token Realm"
,激活该选项即可。
我们先拿Nexus3来搭建一个提供http服务的私服,再用Harbor搭建一个自签发证书的https私服,显然我是没有花钱买过证书的,
当然免费证书现在也是很多中小型公司比较青睐的,使用率比较高的比如:Let's Encrypt,大家可以自行申请,但前提是要有一个可以绑定的域名才行。
Nexus3私服搭建
在【DevOps实战系列】第三章:详解Maven仓库及环境搭建中我们已经搭建好了Nexus3服务器,这里我们就直接复用了,其实他和maven的概念基于相同,区分group、hosted、proxy这几种类型的仓库,只不过Nexus3默认安装后并没有自动给我们创建这些仓库,而是需要我们手动自己创建。
官方地址:https://help.sonatype.com/repomanager3/nexus-repository-administration/formats/docker-registry
Docker容器部署
准备工作:
我们在安装Nexus容器时,只映射了一个端口9081->8081
而根据官网描述,docker仓库不能在上下文路径基础上提供服务,也就意味着我们需要单独提供一个端口为docker仓库服务使用,
根据官网描述,每个hosted仓库都建议有一个独占的端口用于接收客户端镜像的提交,而使用一个端口给group的仓库用于客户端从私服拉取镜像,
所以我们这里至少要指定2个端口,一个给hosted一个给group使用(即一个提交一个拉取),比如9082->8082,9083->8083
其实换到docker的角度就很好理解,docker拉取私服需要先登录到私服,而登录的关键信息就是ip+port,而类比Nexus提供的maven的仓库地址形如:
http://10.10.1.199:9081/nexus/repository/maven-public/,显然docker是无法登录到这样的仓库的,而Nexus针对docker仓库是提供了http或https的服务端口,这样就可以通过【docker login ip+port】来登录到对应的docker仓库,进而进行docker pull或docker push操作。
version: '3'
services:
nexus3:
image: 'sonatype/nexus3:3.17.0'
restart: always
container_name: 'nexus3'
hostname: 'nexus3'
environment:
- NEXUS_CONTEXT=nexus # 默认不指定上下文为根/,这是和nexus2不同的地方
ports:
- '9081:8081'
- '9082:8082'
- '9083:8083'
networks:
- 'exist-net-bloom'
volumes:
- '/docker/nexus3/data:/nexus-data'
- '/etc/timezone:/etc/timezone:ro'
- '/etc/localtime:/etc/localtime:ro'
networks:
exist-net-bloom:
external:
name: devops
重新部署容器:
docker-compose up -d
仓库创建与配置
1.创建proxy类型的docker仓库:
用来作为中心仓库,本地没有的通过代理到中心仓库下载到私服仓库。
操作路径: 设置->Repository->Repositories->create repository->docker(proxy)
除以上配置我有些是偷工减料了,比如Storage,正常为了与其他库隔离,docker可以单独创建一个存储目录,可以到Blob Storage中创建,这里为了方便我们省略了。
[重要属性:Docker Index]:
注意这里我指定的是"Use Docker Hub",他的作用是当我们通过docker pull或docker search的时候,仓库会先到Docker Index指定的服务器去查找镜像的关键信息,找到后再去用完成的镜像标签去镜像源拉取镜像,我们平时使用的标签只不过是一个简化的索引,所以这个Docker Index不能随意指定,否则会找不到镜像,而一般的Docker Index都会和镜像源的地址一起发布,而Docker Hub的索引服务时https://index.docker.io/,所以此处我是用了它,当然也可以手动指定地址https://index.docker.io/;如果大家知道其他索引服务器也可以选择手动指定。
官网出处:https://help.sonatype.com/repomanager3/nexus-repository-administration/formats/docker-registry/proxy-repository-for-docker
一些常用的镜像源列举:
- docker hub:https://registry-1.docker.io
- docker中国:https://registry.docker-cn.com
- 网易:http://hub-mirror.c.163.com
- 腾讯云:https://cloud.tencent.com
- 中科大:http://mirrors.ustc.edu.cn/
注意:
这里的proxy仓库并没有指定http或https端口,其实是可以指定的,如果指定了当然可以单独连接该仓库通过docker pull拉取代理的源中的镜像,但是这里我们主要是要用到group类型的仓库的拉取,他的特点就是可以汇集hosted和proxy多个仓库的镜像,具体可以看后边的测试部分。2.创建hosted类型的docker仓库:用来保存自己构建的镜像
操作路径: 同上,只不过需要指定http的端口,我们这里设置8082,proxy代理仓库因为是代理,并不直接提供服务,所以无需指定端口,而他一般是交给group,由客户端连接group然后拉取所有在group下的仓库的内容,优先拉取本地私服镜像,如果没有的,则由私服拉取proxy代理仓库的镜像。
3.创建group类型的docker仓库:
同maven的group一个意思,是一个虚构的仓库,里边包含了所有仓库镜像的集合(需要创建时手动选择汇总哪些仓库)
实践
1.试错
假设此时没有将仓库地址加入docker信任列表、也没有开启允许docker使用nexus账号登录
错误意思就是请使用https协议,所以我们进行优化,将仓库加入信任列表:
# 进入宿主机操作
vi /etc/docker/daemon.json
# 注意这里因为是通过映射到宿主机的端口访问,所以不是Nexus中设置的8082和8083,而是宿主机的端口
"insecure-registries":[
"10.10.1.199:9082", # 提交时的hosted仓库
"10.10.1.199:9083", # 拉取时用的group仓库
]
# 重启docker使之生效
systemctl restart docker
# 查看配置是否生效
docker info
再次执行:docker login http://10.10.1.199:9083
从错误得知,不再要求https了,而是401认证错误,所以此时我们在没有输错账号密码的情况,就需要开启支持nexus账号登录的功能:
再试
这次没问题,成功连接到group仓库
问题:
但是仔细看日志,可以发现登陆成功后,docker会将密码存入到当前用户home目录的.docker/config.json中,并且是未加密不安全的,打开后我们发现内容如下:
{
"auths": {
"10.10.1.199:9083": {
"auth": "YWRtaW46amllMTIzNDU2" # 该内容为base64编码
}
}
}
# 我们可以使用base64解码,可以发现很容易拿到明文的密码,所以这样是不安全的,这主要看我们实际环境的网络架构,
# 如果有风险docker提供了其他保存密码的方式,大家感兴趣可以自行研究下,这里不是我们的重点就不多说了。
echo 'YWRtaW46amllMTIzNDU2' | base64 --decode
2.镜像拉取/推送环节[完整案例]
从互联网拉取(不使用私服)
docker pull busybox
# 拉取后我们到私服上查看并没有保存该镜像,而是只有宿主机本地有此镜像,说明没有走私服
从group仓库拉取镜像:以busybox镜像为例
# 拉取之前我们先把本地的busybox镜像删除,避免干扰测试
docker rmi busybox:latest
# 登录group仓库
docker login 10.10.1.199:9083
# 通过group仓库拉取镜像
docker pull 10.10.1.199:9083/busybox:latest
我们看结果是报错了,本地并没有拉到镜像,看私服的proxy仓库确实有内容了,这个其实是我们配置的代理仓库的镜像源有问题,
我把163的镜像源换成了我的阿里云镜像源就没有问题了:阿里云镜像源大家到阿里云的容器管理中自己生成一个地址就行了,前边有案例就不多说了。
再次执行结果如下:
再看下私服的proxy仓库:也是拉取到了
从hosted仓库拉取/推送镜像
# 接下来我们把刚拉下来的镜像重新打个标签(标签中指定要上传到的私服仓库地址),上传到私服,即上传到hosted仓库
docker tag 10.10.1.199:9083/busybox:latest 10.10.1.199:9082/busybox:hosted-1.0
# 将打好标签的新镜像,推送到hosted仓库
docker push 10.10.1.199:9082/busybox:hosted-1.0
再从group仓库拉取推送到hosted中的镜像
# 这里我们演示下从group仓库拉取hosted仓库的镜像
# 先删除本地的所有busybox镜像,避免干扰测试
docker rmi 10.10.1.199:9083/busybox:latest
docker pull 10.10.1.199:9083/busybox:hosted-1.0
匿名拉取:
根据我们的配置,是已经开启了允许匿名拉取,下边我们测一下
# 首先我们退出group仓库,退出成功后会将~/.docker/config.json中的密码删除
docker logout 10.10.1.199:9083
# 拉取一个nginx镜像 --> 结果是没问题的。
docker pull 10.10.1.199:9083/nginx