给我一台Linux服务器,借助Harbor搭建私有的Docker镜像中心?

本文最后更新于 2023年12月17日 下午

云原生技术倍受重视,大家也更关注应用的容器化、分布式的部署,通过云原生技术自动化软件录制、测试、发布与部署流程非常方便。

当然,使用云原生技术,拥有一个容器镜像中心非常关键。本次教程,就教大家如何借助Harbor,搭建一个自己的镜像中心,拉取、发布和管理自己的镜像

如果你使用K8S或者是K3S,那么使用本文章的方法,也可以将Harbor作为自己K8S的容器拉取和发布中心。可以很好地解决私有镜像的版本管理、发布、拉取与回滚问题;

如果是内网集群,那么上述操作简直是像吃巧克力一样丝滑

Harbor

Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器,通过添加一些企业必需的功能特性,例如安全、标识和管理等,扩展了开源Docker Distribution。作为一个企业级私有Registry服务器,Harbor提供了更好的性能和安全。提升用户使用Registry构建和运行环境传输镜像的效率。

也就是说,相比于Docker内置Registry

  • 提供基于Web界面的图形化管理界面,操作更友好
  • 支持用户、项目和镜像的访问控制机制
  • 可以对镜像进行扫描查找漏洞,提升安全性
  • 完全支持LDAP/AD等标准化的企业用户管理
  • 可以很好地集成到CI/CD流程中
  • 提供API开放功能,便于第三方系统对接

当然,社区活跃度高,如果出现问题,有机会在社区找到解决方法或者在后续版本内修复。

坏处的话…… 就是旧版本万一因为开源代码内的依赖产生什么漏洞披露,对一些只要能用就一定不更新的企业来说,小概率会比较麻烦~~

为什么自建Docker中心

有些小伙伴可能一时没想清楚为什么要自建Docker镜像中心? 直接拉取官方源或者阿里云镜像不就好了?

确实,如果只是个人学习或者一台只需要公共镜像的服务器,直接使用公共镜像源是比较方便。但是如果需要构建自己的产品、项目镜像、做持续迭代,就需要一处专用的镜像仓库用来存储分发:

  • 方便对产品私有镜像进行版本管理、发布与回滚,支持多环境部署;
  • 产品更新后,可以通过原子操作一键推送新镜像;
  • 镜像构建可以定制化集成到CI/CD流水线中,比如:在GitLab CI/CD的时候,使用自定义镜像直接跳过基础的依赖打包;
  • 支持自己的命名空间,和公有源中的镜像区分开来;
  • 私有源可以配置权限控制,仅开发人员可访问。

而直接使用公共源就难以支撑上述产品镜像研发和持续交付需求。所以自建私有镜像中心是必不可少的。当然,你也可以直接购买阿里云、腾讯云的私有镜像存储方案,也是一个不错的方法。

为什么选择Harbor

其实搭建Docker中心,有很多其他第三方的选择,除了上文直接购买云服务厂商的私有化方案外,还可以用其他类似私有镜像仓库方案;比如: Sonatype Nexus Repository OSS

其实Nexus也可以完成镜像中心的搭建,我之前也用Nexus搭建Maven镜像和NPM镜像,很方便,用Nexus一样也可以搭建Docker的仓库。使用Harbor的优势在于好部署,尤其是设置SSL方面,Harbor容易得多。如果你想用Nexus完全可以。

使用Harbor主要的原因就是:Harbor使用门槛低、(相对)好配置

辅助视频

部分东西,还是视频比较清晰。

这里做个视频,主要内容:

  • Harbor使用效果(配合GitLab CI/CD使用效果)
  • 相关环境准备和操作前提
  • OpenSSL证书自签
  • Harbor的搭建和初始化部署

做教程视频不易(B站根本不会推荐引流),请务必一键三连嗷~

支持创作

制作教程不易,如果热心的小伙伴,想支持创作,可以加入我们的「爱发电」电圈:

当然,也欢迎在B站或YouTube上关注我们:

更多:

操作前提

首先,强烈建议配合官方文档进行操作:

尤其是关于SSL的部分,用OpenSSL进行自签,在激活Nginx HTTPS的同时,用于完成加密传输和其他设备Docker登录加密:
官方关于设置SSL的部分

其次是服务器的配置,目前官方建议硬件上是:

配置信息 最低 推荐
CPU 2 CPU 4 CPU
内存 4 GB 8 GB
存储 40 GB 160 GB

但是我测试一下,实际上2GB内存也够个人和小型团队使用了。

在Linux服务器上的软件方面没什么好说的了,总的来说:

  1. Docker Engine: 最少需要v17.06.0-ce版本;
  2. Docker Compose: 最少需要v1.18.0版本;
  3. OpenSSL: 版本不要过低即可,可以自签证书即可

部署Harbor镜像

教程正式开始,本次使用的Linux版本是: Debian11。

如果你并没有服务器设备,需要一个购买/租借,为大家申请到的专属福利:

另外,也可以考虑:

使用服务器的专属连接,享受超低折扣( ◔ ڼ ◔ )

安装Docker

首先是安装Docker,个人比较喜欢手动使用软件包管理器和阿里云镜像进行Docker的安装:

1
2
3
4
5
6
7
8
9
10
11
12
# 安装基础依赖
sudo apt install apt-transport-https ca-certificates curl gnupg2 software-properties-common
# 添加阿里仓库访问密钥
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# 添加更新源(适用于X86设备),树莓派请改为arm64或者aarch64
sudo add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/debian $(lsb_release -cs) stable"
# 更新
sudo apt update
# 安装Docker相关软件包
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

如果期间出现签名错误:

W: GPG error: https://mirrors.aliyun.com/docker-ce/linux/debian bullseye InRelease: The following signatures couldn’t be verified because the public key is not available: NO_PUBKEY 7EA0A9C3F273FCD8
E: The repository 'https://mirrors.aliyun.com/docker-ce/linux/debian bullseye InRelease' is not signed.

添加签名:

1
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 『签名Key』

添加签名证书
之后再进行后续的操作,Docker应该就安装完成了:
安装Docker成功

当然,你也可以把其他用户归属到Docker的用户组内,方便我们后续使用非root用户直接操作Docker:

1
2
# 添加其他用户在Docker用户组内
sudo usermod -aG docker mintimate

到此,我们的Docker就准备完成了。

下载Harbor安装包

Harbor依赖很多镜像,推荐使用官方的离线版本进行部署,以免因为网络问题,无法在大陆服务器或者内网服务器上部署Harbor依赖的镜像服务。

Harbor安装包的下载地址:Harbor Github Releases: https://github.com/goharbor/harbor/releases

下载离线安装版本的Harbor

解压后,内部的内容大概是这样的:

1
2
3
4
5
6
7
harbor
├── common.sh
├── harbor.v2.7.3.tar.gz
├── harbor.yml.tmpl
├── install.sh
├── LICENSE
└── prepare

到此,前期的准备就完成了。

OpenSSL自签证书

我们需要使用OpenSSL自签证书:

1
2
3
4
5
6
7
# 生成密钥
openssl genrsa -out yourdomain.com.key 4096
# 生成公钥
openssl req -x509 -new -nodes -sha512 -days 3650 \
-subj "/C=CN/ST=Beijing/L=Beijing/O=mintimate/OU=Personal/CN=yourdomain.com" \
-key yourdomain.com.key \
-out yourdomain.com.crt

解释一下公钥参数的含意:

  • -x509: 指定生成自签名X.509证书;
  • -nodes: 指定生成的私钥不加密;
  • -sha512: 指定使用SHA-512哈希算法进行签名。
  • -days 3650: 指定证书的有效期为3650天(约10年)。
  • -subj “/C=CN/ST=Beijing/L=Beijing/O=mintimate/OU=Personal/CN=yourdomain.com”: 指定证书的主题信息。”C”表示国家代码(Country),”ST”表示省/州(State),”L”表示城市(Locality),”O”表示组织(Organization),”OU”表示组织单位(Organizational Unit),”CN”表示通用名称(Common Name)。
  • -key yourdomain.com.key: 指定用于签名证书的私钥文件。
  • -out yourdomain.com.crt: 指定生成的证书文件的输出路径和文件名。

生成十年有效的密钥对

根据生成的密钥和公钥,我们用来生成的证书,进而用于在服务端校验域名对应证书的匹配性;这里创建证书扩展配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
cat > v3.ext <<-EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1=yourdomain.com
DNS.2=yourdomain
DNS.3=hostname
EOF

解释一下:

  • authorityKeyIdentifier=keyid,issuer: 指定证书的颁发者(Issuer)和颁发者的密钥标识符(Key Identifier)。
  • basicConstraints=CA:FALSE: 指定证书不是一个证书颁发机构(CA),而是一个终端实体的证书。
  • keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment: 指定证书的密钥用途,包括数字签名、不可否认性、密钥加密和数据加密。
  • extendedKeyUsage = serverAuth: 指定证书的扩展密钥用途,限制为服务器身份验证。
  • subjectAltName = @alt_names: 指定使用alt_names部分定义的主题备用名称(SAN)扩展字段。

扩展配置文件生成

最后,生成对应的证书:

1
2
3
4
5
6
7
8
9
10
11
12
# 生成一个签名请求
openssl req -sha512 -new \
-subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=yourdomain.com" \
-key yourdomain.com.key \
-out yourdomain.com.csr

# 使用刚刚生成的CA Key签名CSR,加上刚刚的v3.ext内部参数
openssl x509 -req -sha512 -days 3650 \
-extfile v3.ext \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-in yourdomain.com.csr \
-out yourdomain.com.crt

签名完成

记住当前的证书地址,假设为:

  • /home/mintimate/myApplication/harbor/ssl

我们可以接下来的操作。

配置Harbor

官方其实给了一个配置模板,就是解压后文件夹内的harbor.yml.tmpl。我们直接复制一份出来,在其基础上进行更改:

1
cp harbor.yml.tmpl harbor.yml

之后进行更改:
初始化设置

需要注意,因为我准备使用宿主机上的Nginx进行反向代理Harbor,所以我这里设置了:

  • hostname: Harbor访问地址,其实和external_url差不多
  • https/port: 将Harbor对外暴露在8443端口;
  • https/certificate: 使用宿主机的SSL证书文件;
  • https/private_key: 使用宿主机的SSL密钥文件;
  • external_url: 设置通过域名docker.example.com访问。

并且,因为我们使用自己的Nginx进行反向代理Harbor,需要把http/port更改为其他地址,比如:8080、8081。

如果你想直接使用Harbor的Nginx服务,就不需要设置external_url,直接设置上面的hostname即可。

如果你不想使用自己的Nginx进行反向代理,直接用Harbor自带的Nginx;那么,设置内的https端口直接设置为443,并设置外部链接为自己访问域名的https形式。

但是,我个人还是推荐使用Nginx进行反向代理,更加优雅(●’◡’●)ノ♥

然后,使用自带的install脚本进行初始化:

1
sudo ./install

运行初始化脚本

如果之前的配置都没错,那么这时候,docker容器就已经开始运行了:
Harbor容器运行

如果你是直接设置hostname的,那么使用hostname的域名,那么配合https的端口即可访问;

如果你是和我一样,使用external_url的,那么Nginx上面可以这样配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
server{
listen 80;
listen 443 ssl http2;
server_name domain.com;

#HTTP_TO_HTTPS_START
if ($server_port !~ 443){
rewrite ^(/.*)$ https://$host$1 permanent;
}

ssl_certificate /home/mintimate/myApplication/harbor/ssl/domain.com.crt;
ssl_certificate_key /home/mintimate/myApplication/harbor/ssl/domain.com.key;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
add_header Strict-Transport-Security "max-age=31536000";
error_page 497 https://$host$request_uri;

location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass https://127.0.0.1:8443; #注意这里的端口
}
}

到此,Harbor就可以测试访问了。

访问Harbor

接下来,浏览器访问Harbor即可访问。不出意外,我们这样部署会弹出SSL证书校验错误:
SSL错误

原因很简单,我们的SSL证书并不是专业公信机构颁发的,是我们自己使用OpenSSL进行自己签名的。浏览器以为这个证书是伪造的;不过没什么影响,照样可以加密传输,如果不放心,可以检查是不是自己签名的证书:
SSL证书内容

可以看到,就是我们自己签名的十年有效期证书。

因为本身就是我们自己或者团队使用,所以这样的自签就可以了。如果想要对外使用,或者不放心,也可以使用专业机构的SSL证书,代替上文内部所有自签步骤。

我们继续访问,通常情况就可以进入我们Harbor的登录界面了:
Harbor主页

默认的管理员:admin;默认的密码:Harbor12345

到此,Harbor的部署就完成了。我最后再演示使用一下。

演示使用

创建项目

首先,我们在Harbor的控制台创建项目:
在Harbor内创建项目

连接Harbor

在一台需要使用这个Docker镜像中心的另外一台服务器进行Docker登录;前文我们使用的是自签的HTTPS,记得把IP或域名先添加到/etc/docker/daemon.json文件中insecure-registries配置项里,用来设置Docker信任非HTTPS或非公共机构颁发SSL的registry地址。比如:

1
2
3
{
"insecure-registries" : ["192.168.0.100:5000", "harbor.internal.com:80"]
}

设置好后,重启Docker守护进程:

1
sudo systemctl restart docker

最后进行连接:

1
docker login domain.com

输入自己刚刚创建的用户名和密码,如果之前设置正确就可以完成登录:
连接Harbor 成功

推送镜像

我们构建一个镜像试试看,这里我基于node:lts-buster镜像,构建一个包含rsync工具包的镜像,Dockerfile内:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 使用node v18.18镜像
FROM node:lts-buster

WORKDIR /app

RUN bash -c 'echo "deb http://mirrors.cloud.tencent.com/debian/ buster main non-free contrib" > /etc/apt/sources.list'
RUN bash -c 'echo "deb-src http://mirrors.cloud.tencent.com/debian/ buster main non-free contrib" >> /etc/apt/sources.list'
RUN bash -c 'echo "deb http://mirrors.cloud.tencent.com/debian/ buster-updates main non-free contrib" >> /etc/apt/sources.list'
RUN bash -c 'echo "deb-src http://mirrors.cloud.tencent.com/debian/ buster-updates main non-free contrib" >> /etc/apt/sources.list'
RUN bash -c 'echo "deb http://mirrors.cloud.tencent.com/debian/ buster-backports main non-free contrib" >> /etc/apt/sources.list'
RUN bash -c 'echo "deb-src http://mirrors.cloud.tencent.com/debian/ buster-backports main non-free contrib" >> /etc/apt/sources.list'
RUN apt update -y
RUN apt install rsync -y

构建镜像

打包后,使用docker images命令就可以看到我们本地的镜像:
构建完成的镜像

最后,我们进行推送:

1
docker tag my-node:latest doamin.com/test_demo/my-node:latest

推送构建完成的镜像

推送成功后,就可以在Harbor的管理界面看到我们刚刚推送的镜像:
Harbor上的结果查看

升级Harbor

后续发现,Harbor官方已经发布新的版本,那么我们如何进行Harbor的升级?

升级操作,Harbor的不同版本,细节可能有所差异,建议参考官方升级步骤:

简单地说,就是先停止Harbor有关容器,之后进行备份并拉取Harbor的升级工具harbor-migrator,最后,使用高版本的Harbor完成安装。

这里不再过多赘述。

END

好啦,本次的演示就到这里。有自己的私有Docker镜像仓库可以为我们的开发和生产环境带来诸多便利。比如集中管理不同环境的镜像版本,实现一键推送和回滚新版本。同时还可以设置访问权限,区分开发人员和运维人员,提高镜像安全性。甚至也可以无缝集成到CI/CD流水线,实现自动构建和发布。

当然,你也可以用其他的方法。有机会进一步说说基于Harbor扩展我们的项目。



给我一台Linux服务器,借助Harbor搭建私有的Docker镜像中心?
https://www.mintimate.cn/2023/11/26/GuideToHostPrivateDockerCenter/
作者
Mintimate
发布于
2023年11月26日
许可协议