Harbor 是一个 CNCF 基金会托管的开源的可信的云原生 docker registry 项目,可以用于存储、签名、扫描镜像内容,Harbor 通过添加一些常用的功能如安全性、身份权限管理等来扩展 docker registry 项目,此外还支持在 registry 之间复制镜像,还提供更加高级的安全功能,如用户管理、访问控制和活动审计等,在新版本中还添加了 Helm 仓库托管的支持。

Harbor 最核心的功能就是给 docker registry 添加上一层权限保护的功能,要实现这个功能,就需要我们在使用 docker login、pull、push 等命令的时候进行拦截,先进行一些权限相关的校验,再进行操作,其实这一系列的操作 docker registry v2 就已经为我们提供了支持,v2 集成了一个安全认证的功能,将安全认证暴露给外部服务,让外部服务去实现。

本章使用到的yaml文件地址:https://files.cnblogs.com/files/sanduzxcvbnm/harbor_yaml.zip?t=1654757668

Harbor 认证原理

上面我们说了 docker registry v2 将安全认证暴露给了外部服务使用,那么是怎样暴露的呢?我们在命令行中输入 docker login https://registry.qikqiak.com 为例来为大家说明下认证流程:

  • docker client 接收到用户输入的 docker login 命令,将命令转化为调用 engine api 的 RegistryLogin 方法
  • 在 RegistryLogin 方法中通过 http 盗用 registry 服务中的 auth 方法
  • 因为我们这里使用的是 v2 版本的服务,所以会调用 loginV2 方法,在 loginV2 方法中会进行 /v2/ 接口调用,该接口会对请求进行认证
  • 此时的请求中并没有包含 token 信息,认证会失败,返回 401 错误,同时会在 header 中返回去哪里请求认证的服务器地址
  • registry client 端收到上面的返回结果后,便会去返回的认证服务器那里进行认证请求,向认证服务器发送的请求的 header 中包含有加密的用户名和密码
  • 认证服务器从 header 中获取到加密的用户名和密码,这个时候就可以结合实际的认证系统进行认证了,比如从数据库中查询用户认证信息或者对接 ldap 服务进行认证校验
  • 认证成功后,会返回一个 token 信息,client 端会拿着返回的 token 再次向 registry 服务发送请求,这次需要带上得到的 token,请求验证成功,返回状态码就是200了
  • docker client 端接收到返回的200状态码,说明操作成功,在控制台上打印 Login Succeeded 的信息 至此,整个登录过程完成,整个过程可以用下面的流程图来说明:

要完成上面的登录认证过程有两个关键点需要注意:怎样让 registry 服务知道服务认证地址?我们自己提供的认证服务生成的 token 为什么 registry 就能够识别?

对于第一个问题,比较好解决,registry 服务本身就提供了一个配置文件,可以在启动 registry 服务的配置文件中指定上认证服务地址即可,其中有如下这样的一段配置信息:

......
auth:
token:
realm: token-realm
service: token-service
issuer: registry-token-issuer
rootcertbundle: /root/certs/bundle
......

其中 realm 就可以用来指定一个认证服务的地址,下面我们可以看到 Harbor 中该配置的内容。

关于 registry 的配置,可以参考官方文档:https://docs.docker.com/registry/configuration/

第二个问题,就是 registry 怎么能够识别我们返回的 token 文件?如果按照 registry 的要求生成一个 token,是不是 registry 就可以识别了?所以我们需要在我们的认证服务器中按照 registry 的要求生成 token,而不是随便乱生成。那么要怎么生成呢?我们可以在 docker registry 的源码中可以看到 token 是通过 JWT(JSON Web Token)来实现的,所以我们按照要求生成一个 JWT 的 token 就可以了。

对 golang 熟悉的同学可以去 clone 下 Harbor 的代码查看下,Harbor 采用 beego 这个 web 开发框架,源码阅读起来不是特别困难。我们可以很容易的看到 Harbor 中关于上面我们讲解的认证服务部分的实现方法。

安装

由于 Harbor 涉及的组件太多了,所以我们这里用更加便捷的 Helm 来进行安装。首先添加仓库地址:

$ helm repo add harbor https://helm.goharbor.io
"harbor" has been added to your repositories

在安装 Harbor 的时候有很多可以配置的参数,可以在 harbor-helm 项目上进行查看。

比如这里我们将主域名配置为 harbor.k8s.local,通过前面的 Ceph RBD 的 StorageClass 来提供存储,又因为前面我们在安装 GitLab 的时候就已经单独安装了 postgresql 和 reids 两个数据库,所以我们也可以配置 Harbor 使用这两个外置的数据库,这样可以降低资源的使用。但是使用外置的数据库我们需要提前手动创建数据库,比如我们这里使用的 GitLab 提供的数据库,则进入该 Pod 创建 registry、clair、notary_server、notary_signer 这4个数据库:

$ kubectl get pods -n kube-ops -l name=postgresql
NAME READY STATUS RESTARTS AGE
postgresql-6f494df48-frsvp 1/1 Running 0 5d3h
$ kubectl exec -it postgresql-6f494df48-frsvp /bin/bash -n kube-ops
root@postgresql-6f494df48-frsvp:~$ sudo su - postgres
postgres@postgresql-6f494df48-frsvp:~$ psql
psql (10.9 (Ubuntu 10.9-1.pgdg18.04+1))
Type "help" for help. postgres=# CREATE DATABASE registry OWNER postgres; # 创建 registry 数据库
CREATE DATABASE
postgres=# GRANT ALL PRIVILEGES ON DATABASE registry to postgres; # 授权给 postgres 用户
GRANT
postgres=# GRANT ALL PRIVILEGES ON DATABASE registry to gitlab; # 授权给 gitlab 用户
GRANT
# Todo: 用同样的方式创建其他三个数据库:clair、notary_server、notary_signer
......
postgres-# \q # 退出

数据库准备过后,就可以使用我们自己定制的 values 文件来进行安装了,完整的定制的 values 文件如下所示:(harbor-values.yaml)

externalURL: https://harbor.k8s.local
harborAdminPassword: Harbor12345
logLevel: debug expose:
type: ingress
tls:
enabled: true
ingress:
hosts:
core: harbor.k8s.local
notary: notary.k8s.local persistence:
enabled: true
resourcePolicy: "keep"
persistentVolumeClaim:
registry:
# 如果需要做高可用,多个副本的组件则需要使用支持 ReadWriteMany 的后端,ceph rbd 是不支持的,可以使用 cephfs,可以换成前面我们使用的 rook-ceph-fs
storageClass: "rook-ceph-block"
# 如果是高可用的,多个副本组件需要使用 ReadWriteMany,默认为 ReadWriteOnce
accessMode: ReadWriteOnce
size: 50Gi
chartmuseum:
storageClass: "rook-ceph-block"
accessMode: ReadWriteOnce
size: 10Gi
jobservice:
storageClass: "rook-ceph-block"
accessMode: ReadWriteOnce
size: 2Gi database:
type: external
external:
host: "postgresql.kube-ops.svc.cluster.local"
port: "5432"
username: "gitlab"
password: "passw0rd" redis:
type: external
external:
#host: "redis.kube-ops.svc.cluster.local"
#port: "6379"
addr: "redis.kube-ops.svc.cluster.local:6379" # 不再使用host和port,否则使用host和port写法,不会采用配置,而是用默认的192.168.0.2:6379 # 默认为一个副本,如果要做高可用,只需要设置为 replicas >= 2 即可
portal:
replicas: 1
core:
replicas: 1
jobservice:
replicas: 1
registry:
replicas: 1
chartmuseum:
replicas: 1
clair:
replicas: 1
notary:
server:
replicas: 1
signer:
replicas: 1

这些配置信息都是根据 Harbor 的 Chart 包默认的 values 值进行覆盖的。现在我们直接安装即可:

$ helm install myharbor harbor/harbor -f values.yaml -n kube-ops
NAME: myharbor
LAST DEPLOYED: Tue May 12 15:23:15 2020
NAMESPACE: kube-ops
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Please wait for several minutes for Harbor deployment to complete.
Then you should be able to visit the Harbor portal at https://harbor.k8s.local.
For more details, please visit https://github.com/goharbor/harbor.

正常情况下隔一会儿就可以安装成功了:

$ helm ls -n kube-ops
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
myharbor kube-ops 1 2020-05-12 15:23:15.194263 +0800 CST deployed harbor-1.3.21.10.2
$ kubectl get pods -n kube-ops -l app=harbor
NAME READY STATUS RESTARTS AGE
myharbor-harbor-chartmuseum-95f9d9898-mqqnn 1/1 Running 0 40m
myharbor-harbor-clair-79fb8694b4-5dnk5 2/2 Running 10 40m
myharbor-harbor-core-c7bdc46d9-qw9hc 1/1 Running 0 79s
myharbor-harbor-jobservice-549d67dc87-j6hr8 1/1 Running 0 79s
myharbor-harbor-notary-server-9d57d5d9f-9fvbw 1/1 Running 10 40m
myharbor-harbor-notary-signer-658d7886-2ssrl 1/1 Running 10 40m
myharbor-harbor-portal-65588b87db-d7whd 1/1 Running 0 40m
myharbor-harbor-registry-5f7cc9d69d-89hkw 2/2 Running 0 40m

安装完成后,我们就可以将域名 harbor.k8s.local 解析到 Ingress Controller 所在的节点,我们这里使用的仍然是 Traefik,由于我们开启了 KubernetesIngress 支持的,所以我们只需要将域名解析到 Traefik 的 Pod 所在节点即可,然后就可以通过该域名在浏览器中访问了:

$ kubectl get ingress -n kube-ops
NAME HOSTS ADDRESS PORTS AGE
myharbor-harbor-ingress harbor.k8s.local,notary.k8s.local 80, 443 41m

用户名使用默认的 admin,密码则是上面配置的默认 Harbor12345:

登录过后即可进入 Harbor 的 Dashboard 页面:

我们可以看到有很多功能,默认情况下会有一个名叫 library 的项目,该项目默认是公开访问权限的,进入项目可以看到里面还有 Helm Chart 包的管理,可以手动在这里上传,也可以对该项目里面的镜像进行一些其他配置。

推送镜像

现在我们来测试下使用 docker cli 来进行 pull/push 镜像,直接使用 docker login 命令登录:

$ docker login harbor.k8s.local
Username: admin
Password:
INFO[0006] Error logging in to v2 endpoint, trying next endpoint: Get https://harbor.k8s.local/v2/: x509: certificat
e signed by unknown authority
Get https://harbor.k8s.local/v2/: x509: certificate signed by unknown authority

这是因为在使用 docker login 登录的时候会使用 https 的服务,而我们这里是自签名的证书,所以就报错了,我们可以将使用到的 CA 证书文件复制到 /etc/docker/certs.d/harbor.k8s.local 目录下面来解决这个问题(如果该目录不存在,则创建它)。ca.crt 这个证书文件我们可以通过 Ingress 中使用的 Secret 资源对象来提供:

$ kubectl get secret myharbor-harbor-ingress -n kube-ops -o yaml
apiVersion: v1
data:
ca.crt: <ca.crt>
tls.crt: <tls.crt>
tls.key: <tls.key>
kind: Secret
metadata:
creationTimestamp: "2020-05-12T07:23:20Z"
labels:
app: harbor
chart: harbor
heritage: Helm
release: myharbor
name: myharbor-harbor-ingress
namespace: kube-ops
resourceVersion: "67162075"
selfLink: /api/v1/namespaces/kube-ops/secrets/myharbor-harbor-ingress
uid: 10a9d22d-3889-4ac4-87c4-5cda7e701828
type: kubernetes.io/tls

其中 data 区域中 ca.crt 对应的值就是我们需要证书,不过需要注意还需要做一个 base64 的解码,这样证书配置上以后就可以正常访问了。

不过由于上面的方法较为繁琐,所以一般情况下面我们在使用 docker cli 的时候是在 docker 启动参数后面添加一个 --insecure-registry 参数来忽略证书的校验的,在 docker 启动配置文件 /usr/lib/systemd/system/docker.service 中修改ExecStart的启动参数:

ExecStart=/usr/bin/dockerd --insecure-registry harbor.k8s.local

或者在 Docker Daemon 的配置文件中添加:

$ cat /etc/docker/daemon.json
{
"insecure-registries" : [
"harbor.k8s.local"
],
"registry-mirrors" : [
"https://ot2k4d59.mirror.aliyuncs.com/"
]
}

然后保存重启 docker,再使用 docker cli 就没有任何问题了:

$ docker login harbor.k8s.local
Username: admin
Password:
Login Succeeded

比如我们本地现在有一个名为 busybox 的镜像,现在我们想要将该镜像推送到我们的私有仓库中去,应该怎样操作呢?首先我们需要给该镜像重新打一个具有 harbor.k8s.local 前缀的镜像,然后推送的时候就可以识别到推送到哪个镜像仓库:

$ docker tag busybox harbor.k8s.local/library/busybox
$ docker push harbor.k8s.local/library/busybox
The push refers to repository [harbor.k8s.local/library/busybox]
5b0d2d635df8: Pushed
latest: digest: sha256:a2490cec4484ee6c1068ba3a05f89934010c85242f736280b35343483b2264b6 size: 527

推送完成后,我们同样可以在 Portal 页面上看到这个镜像的信息:

镜像 push 成功,同样可以测试下 pull:

$ docker rmi harbor.k8s.local/library/busybox
Untagged: harbor.k8s.local/library/busybox:latest
Untagged: harbor.k8s.local/library/busybox@sha256:a2490cec4484ee6c1068ba3a05f89934010c85242f736280b35343483b2264b6
$ docker rmi busybox
Untagged: busybox:latest
Untagged: busybox@sha256:061ca9704a714ee3e8b80523ec720c64f6209ad3f97c0ff7cb9ec7d19f15149f
$ docker pull harbor.k8s.local/library/busybox:latest
latest: Pulling from library/busybox
e2334dd9fee4: Already exists
Digest: sha256:a2490cec4484ee6c1068ba3a05f89934010c85242f736280b35343483b2264b6
Status: Downloaded newer image for harbor.k8s.local/library/busybox:latest
harbor.k8s.local/library/busybox:latest $ docker images |grep busybox
harbor.k8s.local/library/busybox latest be5888e67be6 3 weeks ago 1.22MB

到这里证明上面我们的私有 docker 仓库搭建成功了,大家可以尝试去创建一个私有的项目,然后创建一个新的用户,使用这个用户来进行 pull/push 镜像,Harbor还具有其他的一些功能,比如镜像复制,大家可以自行测试,感受下 Harbor 和官方自带的 registry 仓库的差别。

高可用

Harbor 的大部分组件都是无状态的应用,比如 portal、core 等只需要增加其相应的副本数量即可;在存储数据层面,需要提供高可用的 Postgresql、Redis 集群,另外针对镜像和 chart 服务也需要提供可持久的存储。

要做高可用的 Harbor,我们需要将数据库通过外置方式进行提供,当然也需要保证数据库是高可用的。然后存储需要允许跨节点数据共享,也就是要支持 ReadWriteMany 模式,我们这里使用 Ceph 的话就需要使用 CephFS。然后将其他组件副本数设置为大于等于2:portal.replicas、core.replicas、jobservice.replicas、registry.replicas、chartmuseum.replicas、clair.replicas、notary.server.replicas 以及 notary.signer.replicas。

然后重新使用 Helm 进行安装即可。

Kubernetes DevOps: Harbor的更多相关文章

  1. Kubernetes DevOps: Jenkins Pipeline (流水线)

    要实现在 Jenkins 中的构建工作,可以有多种方式,我们这里采用比较常用的 Pipeline 这种方式.Pipeline,简单来说,就是一套运行在 Jenkins 上的工作流框架,将原来独立运行于 ...

  2. kubernetes搭建Harbor无坑及Harbor仓库同步

    一.helm搭建harbor 1.安装helm 1.1.安装helm客户端 tar -zxvf helm-v2.14.3-linux-amd64.tar.gz mv linux-amd64/helm ...

  3. Kubernetes DevOps: Tekton

    Tekton 是一款功能非常强大而灵活的 CI/CD 开源的云原生框架.Tekton 的前身是 Knative 项目的 build-pipeline 项目,这个项目是为了给 build 模块增加 pi ...

  4. 基于jenkins,tekton等工具打造kubernetes devops平台

    本贴为目录贴,将不断更新 目录 1.Docker在centos下安装以及常见错误解决 2.使用kubernetes 官网工具kubeadm部署kubernetes(使用阿里云镜像) 3.无法访问gcr ...

  5. Windows下搭建Docker与Kubernetes(DevOps一)

    Docker与Kubernetes (二)搭建 开通  Hyper-V 安装Docker for Windows 开通Kubernetes 3.关键概念 PodKubernetes 中的最小单元,一个 ...

  6. Kubernetes DevOps: Gitlab

    Gitlab 官方提供了 Helm 的方式在 Kubernetes 集群中来快速安装,但是在使用的过程中发现 Helm 提供的 Chart 包中有很多其他额外的配置,所以我们这里使用自定义的方式来安装 ...

  7. Kubernetes DevOps: Jenkins

    提到基于 Kubernete 的CI/CD,可以使用的工具有很多,比如 Jenkins.Gitlab CI 以及新兴的 drone 之类的,我们这里会使用大家最为熟悉的 Jenkins 来做 CI/C ...

  8. 使用Harbor配置Kubernetes私有镜像仓库

    通常情况下,在私有云环境中使用kubernetes时,我们要从docker registry拉取镜像的时候,都会给docker daemo配置–insecure-registry属性来告诉docker ...

  9. kubernetes部署高可用Harbor

    前言 本文Harbor高可用依照Harbor官网部署,主要思路如下,大家可以根据具体情况选择搭建. 部署Postgresql高可用集群.(本文选用Stolon进行管理,请查看文章<kuberne ...

随机推荐

  1. 动画 ---Animejs 简单使用与源码解析

    Anime是什么 Anime有什么用 Anime是作何做的 requireAnimationFrame() engine(){ // 处理让多个帧运动起来 ​ play() ​ step()} ani ...

  2. LEACH分簇算法实现和能量控制算法实现

    一.前言 1.在给定WSN的节点数目(100)前提下,节点随机分布,按照LEACH算法,实现每一轮对WSN的分簇.记录前K轮(k=10)时,网络的分簇情况,即每个节点的角色(簇头或簇成员).标记节点之 ...

  3. 低代码如何构建支持OAuth2.0的后端Web API

    OAuth2.0 OAuth 是一个安全协议,用于保护全球范围内大量且不断增长的Web API.它用于连接不同的网站,还支持原生应用和移动应用于云服务之间的连接,同时它也是各个领域标准协议中的安全层. ...

  4. python+tkinter 的布局

    from tkinter import * win = Tk() win.title("布局") # #窗口标题 win.geometry("600x500+200+20 ...

  5. 2 Zookeeper 单击安装

    (二)Zookeeper 本地模式安装 下载地址 镜像库地址:http://archive.apache.org/dist/zookeeper/ apache-zookeeper-3.6.0.tar. ...

  6. jdbc 05: 查询结果集

    jdbc连接mysql,查询结果集 package com.examples.jdbc.o5_结果集查询; import java.sql.*; import java.util.ResourceBu ...

  7. 基于yum安装CDH集群

    一.环境准备 准备至少3台设备:CentOS7系统: 如果是在实验环境下,给虚拟机的内存至少4G,根建议1T,数据盘1T,由于是虚拟机,所以根分区和数据盘放心大胆的给:如果是在生产环境则多多益善:我这 ...

  8. Windows 安装 Linux 环境

    简介 在实际开发中,我们除了在Windows上进行开发外,可能还需要基于Linux进行一些编译或者测试等,因此,我们可能需要在Windows环境中安装Linux环境,通常可能我们会使用虚拟机替代,但是 ...

  9. 彻底搞懂kubernetes调度框架与插件

    调度框架 [1] 本文基于 kubernetes 1.24 进行分析 调度框架(Scheduling Framework)是Kubernetes 的调度器 kube-scheduler 设计的的可插拔 ...

  10. IDEA自定义liveTemplates(方法模板、类模板)

    IDEA自定义liveTemplates(方法模板.类模板) 前言,搞这个模板有何意义? 降低大家写方法注释的成本,统一风格.有时候不是开发同学不爱写注释,而是没有合适的载体和空间. IDEA模板设置 ...