Skip to main content

moregeek program

devops实战系列【第七章】:详解docker私服harbor篇-多极客编程

个人亲自录制全套DevOps系列实战教程 :​​手把手教你玩转DevOps全栈技术​

DevOps实战系列【第七章】:详解Docker私服Harbor篇_devops

Harbor私服搭建

讲完Nexus3再来看下harbor,其实大同小异,只不过harbor的管理要比Nexus3更专业、功能更完善,大家按需选择即可,Nexus的优势是他能和Maven仓库复用同一个服务器。

官网:​​https://goharbor.io/docs/2.6.0/install-config/installation-prereqs/​

其实Harbor更适合拿一台虚拟机或物理机来安装,当然也可以集成到k8s,但如果是单台docker服务下安装,就有些不太合适了,

不合适的原因是Harbor需要​​docker-engine、docker-compose、openssl​​的支持,即要在装有这些工具包机器上安装Harbor。

​有3种安装方案:​
  • 直接安装在宿主机[复用docker环境][演示https方式]
  • 将harbor安装到容器:手动构建镜像,镜像中安装harbor需要的环境(docker环境等)[演示http方式]
  • 将harbor安装到容器:类似jenkins那样,将需要的环境从宿主机映射到容器(该方式我们不再演示)

下边我们先来演示容器中单独部署Harbor仓库

Docker容器部署[http协议版]


下载安装包:从官方(​​https://github.com/goharbor/harbor/releases​​​)下载harbor稳定版,

离线安装包:harbor-offline-installer-v2.6.2.tgz,大约有769M,如果大家无法访问可以找我索取。

目录:我们依然按照老规矩,将文件拷贝到/docker/harbor目录,目录结构如下,所有资料下文都有。

DevOps实战系列【第七章】:详解Docker私服Harbor篇_devops_02

1.将离线安装包拷贝到目标目录:


/docker/harbor/harbor-offline-installer-v2.6.2.tgz

2.事先准备一个harbor的配置文件:harbor.yml


值得关注的属性如下,其他忽略【此处只需要修改hostname和注释掉https,其他默认即可】

# 因为我要宿主机映射访问,所以此处使用宿主机ip,即访问harbor时使用10.10.1.199
hostname: 10.10.1.199
http:
port: 9090

# 我们优先演示http协议,所以注释掉https(注释掉)
#https:
#port: 9443
#certificate: /cert/certificate/path # 生成的证书目录
#private_key: /cert/private/key/path

# harbor管理员admin的密码(保持默认)
harbor_admin_password: Harbor12345
# 默认存储数据目录
data_volume: /data

# 日志配置:日志级别、输出目录(保持默认)
log:
level: info
local:
location: /var/log/harbor
3.准备一个docker的配置文件:/etc/docker/daemon.json


主要是把镜像加速和信任列表创建好,否则最好映射到宿主,因为毕竟是容器,删除后容易丢失。

"registry-mirrors": [
"https://mtu7rhzd.mirror.aliyuncs.com",
"http://hub-mirror.c.163.com",
"https://docker.mirrors.ustc.edu.cn",
"https://registry.docker-cn.com"
],
"insecure-registries":[
"10.10.1.199:9082",
"10.10.1.199:9083",
"10.10.1.199:9090"
]
4.创建Dockerfile镜像文件:/docker/harbor/Dockerfile


此处使用阿里云的yum源安装docker,也可以用官方:​​https://download.docker.com/linux/centos/docker-ce.repo​

FROM centos:centos7
LABEL maintainer="xxx@126.com"
USER root
COPY * /docker/
WORKDIR /usr/local
RUN set -e \
&& cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo 'Asia/Shanghai' > /etc/timezone \
&& mv -f /docker/harbor-offline-installer-v2.6.2.tgz . \
&& tar -zxf harbor-offline-installer-v2.6.2.tgz \
&& mv -f /docker/harbor.yml harbor \
&& rm -f harbor-offline-installer-v2.6.2.tgz \
&& yum install -y yum-utils \
&& yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker->ce.repo \
&& yum install -y docker-ce docker-ce-cli docker-compose-plugin \
&& mkdir -p /etc/docker/ \
&& mv -f /docker/daemon.json /etc/docker \
&& mv -f /docker/start.sh harbor \
&& chmod 777 harbor/start.sh \
&& chmod 777 /etc/rc.d/rc.local \
&& echo "echo '准备脚本执行...!'" >> /etc/rc.local \
&& echo "sh /usr/local/harbor/start.sh" >> /etc/rc.local \
&& echo "echo '脚本执行完毕!'" >> /etc/rc.local

EXPOSE 9090
EXPOSE 9443

# 这里设置的会被docker-compose.yml中设置的替换掉
CMD ["/usr/sbin/init"]

​大坑:​​​注意我们是基于centos7的镜像构建的,而我们容器内安装有docker-engine,那么肯定要通过systemctl启动服务,而systemctl是需要root权限的,虽然我们Dockerfile指定了USER root,但这只是容器的root,他对于宿主机来说仍然是普通用户,而我们需要启动容器时指定​​privileged: true​​​,这样容器内的root才真正具备root权限,但是正式因为当前基于centos7,而centos7的privileged: true设置是不起作用的,这在官方也提供了解决方法,但是太麻烦,我们采用另一种方式,就是容器启动前先执行​​/usr/sbin/init​​​脚本,即可解决。具体大家可以到官网查询,我这里就不多说了。


官方安装:​​​https://hub.docker.com/_/centos​​​ -> 正文部分在解决Systemd的位置,可以自行选择。


​​​第二个坑:​​​容器中我们安装了docker服务,那么肯定是要通过systemctl start docker来启动,但是要想让systemctl能执行就需要开启init进程,init进程必须在系统启动的时候开启,作为第一个进程,init无法在脚本中启动,因此只能是将容器的启动命令设置成/usr/sbin/init,然后将启动服务的命令写成脚本,再把执行脚本的命令写入/etc/rc.local中,这样就可以在centos7容器中使用systemctl启动服务了。


​​​第三个坑:​​​按照上述操作其实还有个坑,就是发现放到rc.local的代码并没有执行,这是因为centos7开始/etc/rc.d/rc.local的权限变成了644,并没有执行权限,而我们修改的是/etc/rc.local,他是软连接到/etc/rc.d/rc.local,所以我们还需要给/etc/rc.d/rc.local授权 chmod +x /etc/rc.d/rc.local,并且我们要先检查一下rc.local服务是否启动,如果没启动还需要让他也向docker一样随机启动(systemctl status rc-local.service/systemctl enable rc-local.service)


5.容器启动脚本vi /docker/harbor/start.sh
#!/bin/bash
logfile=/var/log/harbor/harbor-run.log
set -e && systemctl start docker >> $logfile && /usr/local/harbor/prepare >> $logfile && >/usr/local/harbor/install.sh >> $logfile
6.创建docker-compose.yml编排脚本:vi /docker/harbor/docker-compose.yml
version: '3'
services:
harbor:
build:
context: .
dockerfile: Dockerfile
image: 'lij/harbor:2.6.2-centos7'
restart: always
container_name: 'harbor'
hostname: 'harbor'
user: root
ports:
- '9090:9090'
- '9443:9443'
networks:
- 'exist-net-bloom'
volumes:
- '/docker/harbor/log:/var/log/harbor'
- '/docker/harbor/data:/data'
privileged: true
networks:
exist-net-bloom:
external:
name: devops

​注意:​​​harbor的配置文件端口我们从80改成了9090,保持了和宿主机映射的端口一致,为什么呢?


经过我的实践,如果容器中使用80,宿主机使用9090,这样映射访问harbor的web页面是没问题的,但是通过docker login 10.10.1.199:9090时就会访问不到。

7.构建部署镜像

宿主机执行部署:./docker/harbor/docker-compose up -d --build

DevOps实战系列【第七章】:详解Docker私服Harbor篇_devops_03


看到这样的日志表示启动完成,而容器内部其实是启动了多个容器:

DevOps实战系列【第七章】:详解Docker私服Harbor篇_docker_04

8.验证:浏览器中输入10.10.1.199:9090

输入默认用户admin,密码Harbor12345

DevOps实战系列【第七章】:详解Docker私服Harbor篇_devops_05

9.客户端登录试试:

宿主机中执行docker login 10.10.1.199:9090,结果却报错了

Error response from daemon: Get "https://10.10.1.199:9090/v2/": http: server gave HTTP response to HTTPS client


我们不是已经加入到信任列表了吗?==>注意我们是把harbor服务地址加入到了自身容器中,而没有加入到宿主机,而此时是使用宿主机访问,所以要加入到宿主机


加入后重启宿主机docker服务再试,就没问题了。

宿主机部署Harbor[https协议版]


1.数字证书

这里我们使用openssl工具来生成证书,其实我们会经常遇到ssh-keygen、openssl、keytool,甚至有时候会用到puttygen,这里简单说明下他们的关系:

完全参考官方文档安装:​​https://goharbor.io/docs/2.6.0/install-config/configure-https/​

2.生成CA根证书

生产中我们需要到CA机构申请证书,而此时我们自己生成CA证书,自己给自己签发证书

# 生成RSA私钥:当前目录生成密钥长度为4096的RSA私钥,输出文件名为ca.key
openssl genrsa -out ca.key 4096

# 生成证书:根据RSA私钥生成证书文件,通过key指定RSA私钥文件,out指定生成的证书文件名,其中subj中要指定申请证书的组织信息,
# 主要将CN指定成harbor所在机器的域名即可,我们这里就是宿主机了,我们将宿主机域名定义成【omv.local】
openssl req -x509 -new -nodes -sha512 -days 3650 \
-subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=omv.local" \
-key ca.key \
-out ca.crt
3.生成自签名证书:即服务端(harbor)要使用的证书
# 生成私钥:使用域名定义私钥文件名
openssl genrsa -out omv.local.key 4096

# 生成服务端证书签名请求:证书请求是向CA发起申请证书的数据格式
openssl req -sha512 -new \
-subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=omv.local" \
-key omv.local.key \
-out omv.local.csr

# 生成x509 v3扩展文件:根据官网要求执行
cat > v3.ext <<-EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
vsubjectAltName = @alt_names

[alt_names]
DNS.1=omv.local
DNS.2=omv
EOF

# 使用该v3.ext文件为你的Harbor主机生成证书,即将自己的证书申请,提交给CA,然后由CA生成证书,只不过此处CA是自己
openssl x509 -req -sha512 -days 3650 \
-extfile v3.ext \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-in omv.local.csr \
-out omv.local.crt
4.将证书配置给Harbor和Docker(harbor所在机器的Docker服务)
# 将自签名证书配置给harbor,即拷贝对应的文件到harbor.yml中配置指定的路径
certificate: /docker/harbor/harbor/cert/omv.local.crt
private_key: /docker/harbor/harbor/cert/omv.local.key

# 将omv.local.crt转换成omv.local.cert,因为docker-engine将crt认为是证书,而cert认为是客户端证书,我们要使用客户端连接harbor
openssl x509 -inform PEM -in omv.local.crt -out omv.local.cert
# 将对应的证书拷贝到docker服务的证书目录(需要手动创建 mkdir -p /etc/docker/certs.d/omv.local/)
# 注意创建的omv.local目录,只能通过https://ommv.local访问,如果端口不是443,则目录需要带上端口,如/etc/docker/certs.d/omv.local:9443/
cp omv.local.cert /etc/docker/certs.d/omv.local/
cp omv.local.key /etc/docker/certs.d/omv.local/
cp ca.crt /etc/docker/certs.d/omv.local/
# 重启docker服务
systemctl restart docker
5.启动harbor:将harbor.yml的https节点打开
./prepare

​出错了:​​​DevOps实战系列【第七章】:详解Docker私服Harbor篇_devops_06


提示我们目录或文件不存在:No such file or directory: '/hostfs/docker/harbor/harbor/data/cert/omv.local.key'
​​​但是这个目录/hostfs哪来的?​
我们知道了harbor是在docker容器中运行,那么prepare脚本应该也是去创建容器了,打开这个脚本,我们发现以下代码:

# 显然是在发布容器,而hostfs正式容器内部的目录,要映射到外部目录/下
docker run --rm -v $input_dir:/input \
-v $data_path:/data \
-v $harbor_prepare_path:/compose_location \
-v $config_dir:/config \
-v /:/hostfs \
--privileged \
goharbor/prepare:v2.6.2 prepare $@

# 我们做一下改造:将我的证书目录映射过去
docker run --rm -v $input_dir:/input \
-v $data_path:/data \
-v $harbor_prepare_path:/compose_location \
-v $config_dir:/config \
-v /docker/harbor/harbor/data/cert:/hostfs/docker/harbor/harbor/data/cert \
--privileged \
goharbor/prepare:v2.6.2 prepare $@

DevOps实战系列【第七章】:详解Docker私服Harbor篇_docker_07


再次执行ok!

# 进行启动
./install.sh

DevOps实战系列【第七章】:详解Docker私服Harbor篇_harbor_08


​问题:​​​该问题是启动harbor相关的nginx容器时遇到宿主机80端口被占用的情况,我是因为omv主机服务的端口用了80


​​​有两种修改方法:​

  • 修改omv更换成其他端口
  • 修改harbor的nginx容器成其他端口:很简单,打开harbor目录,​​此时因为运行了install.sh​​​,已经生成了docker-compose.yml,我们打开找到位置修改端口即可DevOps实战系列【第七章】:详解Docker私服Harbor篇_devops_09

  • 再启动
  • DevOps实战系列【第七章】:详解Docker私服Harbor篇_harbor_10
6.验证浏览器使用:

输入​​https://10.10.1.199​​​,注意此时使用的是https,所以默认不输入端口默认使用443,而上边我们看到80和443都已放开,只不过没使用80端口


那没使用上边为什么报错呢?因为即便没使用但是我们做了映射啊,所以上边还有第3种方法,就是不映射80端口,只映射443端口即可,​​​但是默认harbor各容器内部通信是使用http协议的,并且各容器并未配置link连接(由docker-compose.yml可知)​​​,所以关闭80映射是影响内部通信大家可以测试一下。如果想把内部通信方式改为https其实和harbor对外https修改方式大同小异,可参看官方文档,这里就不演示了。

内部通信https配置官方文档:​​​​​https://goharbor.io/docs/2.6.0/install-config/configure-internal-tls/​​​DevOps实战系列【第七章】:详解Docker私服Harbor篇_docker_11


因为我们使用的自签名证书,所以浏览器从服务端拿到证书后是无法通过已知的CA认证机构校验的,所以需要我们自己将证书加入到浏览器的信任列表,我们此处选择继续访问即可。


和docker容器方式一样可以正常访问,此处不截图了,避免重复。

7.验证Docker推送和拉取

docker的使用,这里和Nexus有些区别,harbor同nexus一样,都是需要我们自己创建仓库的,只不过nexus每个仓库我们可以单独指定端口,而harbor则不可以,


所以为了区分拉取/推送哪个仓库,我们需要打标签时加上namespace(即仓库名),而nexus则可以通过端口来区分。


我们先来创建一个仓库:从页面可知也可以创建代理仓库,此处我们选择公开,即允许匿名拉取。

DevOps实战系列【第七章】:详解Docker私服Harbor篇_harbor_12


进入仓库,可以看到有很多配置功能,这也是他比nexus强大的地方之一,比如webhooks可以对接harbor仓库的10几个事件通知,方便我们做监控。

DevOps实战系列【第七章】:详解Docker私服Harbor篇_harbor_13


进入"镜像仓库"选项卡,我们可以看到镜像列表,右侧有推送命令,大家可以自行查看

DevOps实战系列【第七章】:详解Docker私服Harbor篇_docker_14

# 先来拉取一下busybox:注意我们使用https,所以要使用域名访问
# 如果大家域名不能访问需要将harbor服务器的hosts进行映射,即10.10.1.199 omv.local配上
docker pull omv.local/test/busybox:latest

DevOps实战系列【第七章】:详解Docker私服Harbor篇_docker_15


显然我们并不存在这样的镜像。

# 从公网拉取镜像busybox
docker pull busybox
# 打私服标签
docker tag busybox:latest omv.local/test/busybox:v1.0
# 登录私服
docker login -u admin -p Harbor12345 omv.local
# 推送镜像
docker push omv.local/test/busybox:v1.0
# 删除本地busybox镜像
docker rmi -f omv.local/test/busybox:v1.0
# 拉取镜像
docker pull omv.local/test/busybox:v1.0

​疑惑1:​​​其实通过界面对比Nexus我们会有些疑惑,Nexus有group仓库,可以汇总所有仓库内容,方便拉取,那么harbor有吗?


为此harbor提供了机器人账号,可以通过创建机器人账号关联多个仓库,这样我们使用机器人账号就可以使用多个仓库的镜像。


​​​疑惑2:​​​Nexus有proxy仓库,可以作为镜像代理仓库,harbor有吗?


harbor是从v2.1.1版本开始增加了这个功能,通过新建"目标"指定外网仓库,然后新建工程指定为代理,以此实现

DevOps实战系列【第七章】:详解Docker私服Harbor篇_devops_16


​​​注意:​​​拉取时我们除了要加项目名到url中还需要增加一个library名称空间,来表名使用代理仓库


如:docker pull omv.local/hub/library/busybox ,这样才可以


具体可见官方文档:​​​https://goharbor.io/docs/2.6.0/administration/configure-proxy-cache/​


8.Nexus和Harbor对比:

各有长处,大家自行选择即可,下边演示我使用的nexus。

  • Nexus使用更加方便
  • Harbor对镜像的管理更加强大

©著作权归作者所有:来自51CTO博客作者上树的蜗牛儿的原创作品,请联系作者获取转载授权,否则将追究法律责任

devops实战系列【第十章】:详解jenkins pipeline基本概念和语法-多极客编程

个人亲自录制全套DevOps系列实战教程 :​​手把手教你玩转DevOps全栈技术​​流水线基本概念官方中文手册: ​​​https://www.jenkins.io/zh/doc/book/pipeline​​​​我们最好在结合英文文档去看,因为翻译过来的中文比较乱。​​Jenkins pipeline是一套插件,它支持实现和集成 continuous delivery pipelines 到J

devops实战系列【第八章】:详解jenkins集成docker私服nexus3-多极客编程

个人亲自录制全套DevOps系列实战教程 :​​手把手教你玩转DevOps全栈技术​​Jenkins集成Docker镜像仓库docker私服已经搭建完毕,下边我们期望jenkins做的事是:①通过git拉取代码②通过maven构建生成jar包③构建含有jar包的镜像​​④推送到docker仓库​​​​⑤通知宿主从仓库拉取镜像并启动容器​​​​有什么好处?​​避免将jar包拷贝到宿主机,而是直接将j

devops实战系列【第三章】:详解maven仓库及环境搭建-多极客编程

个人亲自录制全套DevOps系列实战教程 :​​手把手教你玩转DevOps全栈技术​​Maven私有仓库,就不多说了,我们这里选用最新的Nexus3的3.17版本,平时公司使用的都是Nexus 2.x,新的3.x版本做了很多的升级,包括存储方式等,这里选用新版本的一个原因就是也想了解下新版本的变化。参考官网: ​​https://help.sonatype.com/repomanager3/ins

一站式云原生体验|龙蜥云原生acns + rainbond-多极客编程

关于 ACNS 龙蜥云原生套件 OpenAnolis Cloud Native Suite(ACNS)是由龙蜥社区云原生 SIG 推出的基于 Kubernetes 发行版本为基础而集成的套件能力,可以提供一键式部署,开箱即用,以及丰富的云原生基础能力,主要包括: Kubernetes 基于 ACK-D , 作为开源的发行版以及 ACK 的下游,ACK-D 经过大规模的生产的验证,保证了组件的稳

47-docker-dockerfile镜像创建自动化生产案例-多极客编程

基于容器手动制作镜像步骤具体如下:下载一个系统的官方基础镜像,如: CentOS 或 Ubuntu基于基础镜像启动一个容器,并进入到容器在容器里面做配置操作 安装基础命令 配置运行环境 安装服务和配置服务 放业务程序代码提交为一个新镜像 docker commit基于自己的的镜像创建容器并测试访问注意:手动制作镜像的方式显示全部的容器制作过程比较困难,且需要前台执行方式添加命令不支持自动化,生产不

nginx的安装配置最全最新-多极客编程

yum安装(最简单)# 命令来一建安装,搞定yum install -y nginx通过yum安装的Nginx的配置文件可能位于/etc/nginx/nginx.conf。1.安装编译环境所需依赖包# linux版本的需要先进行源码编译,编译时需要gcc环境yum install -y gcc-c++# pcre是一个perl的库,包括perl兼容的正则表达式库。nginx的http模块会使用pc

devops实战系列【第十章】:详解jenkins pipeline基本概念和语法-多极客编程

个人亲自录制全套DevOps系列实战教程 :​​手把手教你玩转DevOps全栈技术​​流水线基本概念官方中文手册: ​​​https://www.jenkins.io/zh/doc/book/pipeline​​​​我们最好在结合英文文档去看,因为翻译过来的中文比较乱。​​Jenkins pipeline是一套插件,它支持实现和集成 continuous delivery pipelines 到J

devops实战系列【第八章】:详解jenkins集成docker私服nexus3-多极客编程

个人亲自录制全套DevOps系列实战教程 :​​手把手教你玩转DevOps全栈技术​​Jenkins集成Docker镜像仓库docker私服已经搭建完毕,下边我们期望jenkins做的事是:①通过git拉取代码②通过maven构建生成jar包③构建含有jar包的镜像​​④推送到docker仓库​​​​⑤通知宿主从仓库拉取镜像并启动容器​​​​有什么好处?​​避免将jar包拷贝到宿主机,而是直接将j

devops实战系列【第三章】:详解maven仓库及环境搭建-多极客编程

个人亲自录制全套DevOps系列实战教程 :​​手把手教你玩转DevOps全栈技术​​Maven私有仓库,就不多说了,我们这里选用最新的Nexus3的3.17版本,平时公司使用的都是Nexus 2.x,新的3.x版本做了很多的升级,包括存储方式等,这里选用新版本的一个原因就是也想了解下新版本的变化。参考官网: ​​https://help.sonatype.com/repomanager3/ins

47-docker-dockerfile镜像创建自动化生产案例-多极客编程

基于容器手动制作镜像步骤具体如下:下载一个系统的官方基础镜像,如: CentOS 或 Ubuntu基于基础镜像启动一个容器,并进入到容器在容器里面做配置操作 安装基础命令 配置运行环境 安装服务和配置服务 放业务程序代码提交为一个新镜像 docker commit基于自己的的镜像创建容器并测试访问注意:手动制作镜像的方式显示全部的容器制作过程比较困难,且需要前台执行方式添加命令不支持自动化,生产不

48-docker-多容器数据共享及持久化-多极客编程

Docker镜像数据读写原理Docker镜像由多个只读层叠加而成,启动容器时,Docker会加载只读镜像层并在镜像栈顶部添加一个读写层如果运行中的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,只是已经被读写层中该文件的副本所隐藏,此即“写时复制(COW copyon write)"机制COW机制节约空间,但会导致性低下,虽然关闭重启容器