标签 docker 下的文章

解决登录Harbor Registry时鉴权失败的问题

今天在测试之前搭建好的高可用Harbor时,发现了一个问题:使用docker login harbor时,有时成功,有时失败:

# docker login -u user -p passwd http://hub.my-domain.com:36666
Login Succeeded

# docker login -u user -p passwd http://hub.my-domain.com:36666
Error response from daemon: login attempt to http://hub.my-domain.com:36666/v2/ failed with status: 401 Unauthorized

我们在DNS中将hub.my-domain.com这个域名解析成两个IP,分别是两个Harbor节点的public IP,这可能是问题的诱发原因,但我还不知道问题根源在哪里。以下是问题的查找过程记录。

1、保证每个Harbor node都是可以login ok的

我在client端通过修改/etc/hosts将hub.my-domain.com分别解析成上述说到的两个node IP并测试。测试结果表明:无论单独解析成哪个IP,docker login http://hub.my-domain.com:36666都会100%的成功。

2、查看两个Harbor node上的registry log,弄清问题现象

将/etc/hosts中hub.my-domain.com的硬解析删除,恢复DNS解析。打开两个terminal tab分别监视连个Harbor node上的registry的日志。经过几次测试,发现一个现象:当docker login成功时,都是一个node上的日志出现更新;而当docker login fail时,我们会看到两个Node上的registry日志都有变化,似乎请求发给了两个node

node1:
Jun 15 14:40:01 172.19.0.1 registry[30242]: time="2017-06-15T06:40:01.245822446Z" level=debug msg="authorizing request" go.version=go1.7.3 http.request.host="hub.my-domain.com:36666" http.request.id=62add46e-e176-4eb8-b36a-84a9fbe7ac9c http.request.method=GET http.request.remoteaddr=xx.xx.xx.xx http.request.uri="/v2/" http.request.useragent="docker/1.12.5 go/go1.6.4 git-commit/7392c3b kernel/4.4.0-58-generic os/linux arch/amd64 UpstreamClient(Docker-Client/1.12.5 \\(linux\\))" instance.id=43380207-7b61-4d45-b06a-a017c9a075af service=registry version="v2.4.1+unknown"

Jun 15 14:40:01 172.19.0.1 registry[30242]: time="2017-06-15T06:40:01.246002519Z" level=error msg="token signed by untrusted key with ID: \"BASH:RNPJ:PEBU:7THG:2NAR:OSFV:CG6U:ANV4:CCNB:ODZR:4BL6:TMD6\""

node2:

Jun 15 14:40:01 172.18.0.1 registry[28674]: time="2017-06-15T06:40:01.213604228Z" level=debug msg="authorizing request" go.version=go1.7.3 http.request.host="hub.my-domain.com:36666" http.request.id=bb6eeb8f-99f1-47a0-8cae-dae9b402b758 http.request.method=GET http.request.remoteaddr=xx.xx.xx.xx http.request.uri="/v2/" http.request.useragent="docker/1.12.5 go/go1.6.4 git-commit/7392c3b kernel/4.4.0-58-generic os/linux arch/amd64 UpstreamClient(Docker-Client/1.12.5 \\(linux\\))" instance.id=2a364e0c-425f-47a9-b144-887d439243ba service=registry version="v2.4.1+unknown"

Jun 15 14:40:01 172.18.0.1 registry[28674]: time="2017-06-15T06:40:01.21374491Z" level=warning msg="error authorizing context: authorization token required" go.version=go1.7.3 http.request.host="hub.my-domain.com:36666" http.request.id=bb6eeb8f-99f1-47a0-8cae-dae9b402b758 http.request.method=GET http.request.remoteaddr=xx.xx.xx.xx http.request.uri="/v2/" http.request.useragent="docker/1.12.5 go/go1.6.4 git-commit/7392c3b kernel/4.4.0-58-generic os/linux arch/amd64 UpstreamClient(Docker-Client/1.12.5 \\(linux\\))" instance.id=2a364e0c-425f-47a9-b144-887d439243ba service=registry version="v2.4.1+unknown"

Jun 15 14:40:01 172.18.0.1 registry[28674]: 172.18.0.3 - - [15/Jun/2017:06:40:01 +0000] "GET /v2/ HTTP/1.1" 401 87 "" "docker/1.12.5 go/go1.6.4 git-commit/7392c3b kernel/4.4.0-58-generic os/linux arch/amd64 UpstreamClient(Docker-Client/1.12.5 \\(linux\\))"

3、探寻Harbor原理,弄清问题根源

打开harbor在github.com的wiki页,在”Architecture Overview of Harbor“中我找到了docker login的流程:

img{512x368}

从图片上,我一眼就看到了从docker client发出的*”两个请求: a和c流程”,看来docker client的确不止一次向Harbor发起了请求。wiki上对docker login流程给了简明扼要的解释。大致的流程是:

  • docker向registry发起请求,由于registry是基于token auth的,因此registry回复应答,告诉docker client去哪个URL去获取token;
  • docker client根据应答中的URL向token service(ui)发起请求,通过user和passwd获取token;如果user和passwd在db中通过了验证,那么token service将用自己的私钥(harbor/common/config/ui/private_key.pem)生成一个token,返回给docker client端;
  • docker client获得token后再向registry发起login请求,registry用自己的证书(harbor/common/config/registry/root.crt)对token进行校验。通过则返回成功,否则返回失败。

从这个原理,我们可以知道问题就出在docker client多次向Harbor发起请求这个环节:对于每次请求,DNS会将域名可能解析为不同IP,因此不同请求可能落到不同的node上。这样当docker client拿着node1上token service分配的token去到node2的registry上鉴权时,就会出现鉴权失败的情况。

4、统一私钥和证书,问题得以解决

token service的私钥(harbor/common/config/ui/private_key.pem)和registry的证书(harbor/common/config/registry/root.crt)都是在prepare时生成的,两个节点都独立prepare过,因此两个node上的private_key.pem和root.crt是不同的,这就是问题根源。

解决这个问题很简单,就是统一私钥和证书。比如:将node1上的private_key.pem和root.crt复制到node2上,并重新创建node2上的container:

// node2上

将node1上的harbor/common/config/ui/private_key.pem复制到node2上的harbor/common/config/ui/private_key.pem;
将node1上的harbor/common/config/registry/root.crt复制到harbor/common/config/registry/root.crt;

$ docker-compose down -v
$ docker-compose up -d

更换了private_key.pem和root.crt的node2上的Harbor启动后,再进行login测试,就会100%成功了!

# docker login -u admin -p passwd http://hub.my-domain.com:36666
Login Succeeded

微博:@tonybai_cn
微信公众号:iamtonybai
github.com: https://github.com/bigwhite

基于Harbor和CephFS搭建高可用Private Registry

我们有给客户搭建私有容器仓库的需求。开源的私有容器registry可供选择的不多,除了docker官方的distribution之外,比较知名的是VMware China出品的Harbor,我们选择了harbor。

harbor在docker distribution的基础上增加了一些安全、访问控制、管理的功能以满足企业对于镜像仓库的需求。harbor以docker-compose的规范形式组织各个组件,并通过docker-compose工具进行启停。

不过,harbor默认的安装配置是针对single node的,要想做得可靠性高一些,我们需要自己探索一些可行的方案。本文将结合harbor和CephFS搭建一个满足企业高可用性需求的private registry。

一、实验环境

这里用两台阿里云ECS作为harbor的工作节点:

node1:  10.47.217.91
node2:  10.28.61.30

两台主机运行的都是Ubuntu 16.04.1 LTS (GNU/Linux 4.4.0-58-generic x86_64),使用root用户。

docker版本与docker-compose的版本如下:

# docker version
Client:
 Version:      1.12.5
 API version:  1.24
 Go version:   go1.6.4
 Git commit:   7392c3b
 Built:        Fri Dec 16 02:42:17 2016
 OS/Arch:      linux/amd64

Server:
 Version:      1.12.5
 API version:  1.24
 Go version:   go1.6.4
 Git commit:   7392c3b
 Built:        Fri Dec 16 02:42:17 2016
 OS/Arch:      linux/amd64

# docker-compose -v
docker-compose version 1.12.0, build b31ff33

ceph版本如下:

# ceph -v
ceph version 10.2.7

ceph的安装和配置可参考这里

二、方案思路

首先,从部署上说,我们需要的Private Registry是独立于k8s cluster存在的,即在k8s cluster外部,其存储和管理的镜像供k8s cluster 组件以及运行于k8s cluster上的应用使用。

其次,企业对registry有高可用需求,但我们也要有折中,我们的目标并不是理想的完全高可用,那样投入成本可能有些高。一般企业环境下更注重数据安全。因此首要保证harbor的数据安全,这样即便harbor实例宕掉,保证数据依然不会丢失即可。并且生产环境下registry的使用很难称得上高频,对镜像仓库的性能要求也没那么高。这种情况下,harbor的高可用至少有两种方案:

  • 多harbor实例共享后端存储
  • 多harbor实例相互数据同步(通过配置两个harbor相互复制镜像数据)

harbor原生支持双实例的镜像数据同步。不过这里我们采用第一种方案:即多harbor实例共享后端存储,因为我们有现成的cephfs供harbor使用。理想的方案示意图如下:

img{512x368}

  • 每个安放harbor实例的node都mount cephfs;
  • 每个node上的harbor实例(包含组件:ui、db、registry等)都volume mount node上的cephfs mount路径;
  • 通过Load Balance将request流量负载到各个harbor实例上。

但这样做可行么?如果这么做,Harbor实例里的mysql container就会“抱怨”:

May 17 22:45:45 172.19.0.1 mysql[12110]: 2017-05-17 14:45:45 1 [ERROR] InnoDB: Unable to lock ./ibdata1, error: 11
May 17 22:45:45 172.19.0.1 mysql[12110]: 2017-05-17 14:45:45 1 [Note] InnoDB: Check that you do not already have another mysqld process using the same InnoDB data or log files.

MySQL多个实例无法共享一份mysql数据文件。

那么,我们会考虑将harbor连接的mysql放到外面来,使用external database;同时考虑到session共享,我们还需要增加一个存储session信息的redis cluster,这样一来,方案示意图变更如下:

img{512x368}

图中的mysql、redis你即可以用cluster,也可以用单点,还是看你的需求和投入。如果你具备现成的mysql cluster和redis cluster,那么直接用就好了。但是如果你没有,并且你还不想投入这么多(尤其是搞mysql cluster),那么用单点就好了。考虑到数据安全,可以将单点mysql的数据存储在cephfs上,如果你已经有了现成的cephfs。

三、在一个node上安装Harbor

1、初装步骤

以一个node上的Harbor安装为例,harbor提供了详细的安装步骤文档,我们按照步骤逐步进行即可(这里我使用的是1.1.0版本,截至目前为止的最新稳定版本为1.1.1版本):

~/harbor-install# wget -c https://github.com/vmware/harbor/releases/download/v1.1.0/harbor-offline-installer-v1.1.0.tgz

~/harbor-install# tar zxvf harbor-offline-installer-v1.1.0.tgz

~/harbor-install/harbor# ls -F
common/  docker-compose.notary.yml  docker-compose.yml  harbor.cfg  harbor.v1.1.0.tar.gz  install.sh*  LICENSE  NOTICE  prepare*

~/harbor-install/harbor./install.sh

[Step 0]: checking installation environment ...

Note: docker version: 1.12.5
Note: docker-compose version: 1.12.0
[Step 1]: loading Harbor images ...
... ...
[Step 2]: preparing environment ...
Generated and saved secret to file: /data/secretkey
Generated configuration file: ./common/config/nginx/nginx.conf
Generated configuration file: ./common/config/adminserver/env
Generated configuration file: ./common/config/ui/env
Generated configuration file: ./common/config/registry/config.yml
Generated configuration file: ./common/config/db/env
Generated configuration file: ./common/config/jobservice/env
Generated configuration file: ./common/config/jobservice/app.conf
Generated configuration file: ./common/config/ui/app.conf
Generated certificate, key file: ./common/config/ui/private_key.pem, cert file: ./common/config/registry/root.crt
The configuration files are ready, please use docker-compose to start the service.

[Step 3]: checking existing instance of Harbor ...
[Step 4]: starting Harbor ...

Creating network "harbor_harbor" with the default driver
Creating harbor-log
Creating harbor-db
Creating registry
Creating harbor-adminserver
Creating harbor-ui
Creating nginx
Creating harbor-jobservice

ERROR: for proxy  Cannot start service proxy: driver failed programming external connectivity on endpoint nginx (fdeb3e538d5f8d714ea5c79a9f3f127f05f7ba5d519e09c4c30ef81f40b2fe77): Error starting userland proxy: listen tcp 0.0.0.0:80: bind: address already in use

harbor实例默认的监听端口是80,但一般node上的80口都会被占用,因此我们需要修改一个端口号。注意:此时harbor仅启动成功了一些container而已,尚无法正常工作。

2、修改harbor proxy组件的listen端口

harbor的proxy组件就是一个nginx,通过nginx这个反向代理,将不同的服务请求分发到内部其他组件中去。nginx默认监听node的80端口,我们用8060端口替代80端口需要进行两处配置修改:

1、harbor.cfg

hostname = node_public_ip:8060

2、docker-compose.yml

proxy:
    image: vmware/nginx:1.11.5-patched
    container_name: nginx
    restart: always
    volumes:
      - ./common/config/nginx:/etc/nginx:z
    networks:
      - harbor
    ports:
      - 8060:80   <--- 修改端口映射
      - 443:443
      - 4443:4443

由于我们修改了harbor.cfg文件,我们需要重新prepare一下,执行下面命令:

# docker-compose down -v
Stopping harbor-jobservice ... done
Stopping nginx ... done
Stopping harbor-ui ... done
Stopping harbor-db ... done
Stopping registry ... done
Stopping harbor-adminserver ... done
Stopping harbor-log ... done
Removing harbor-jobservice ... done
Removing nginx ... done
Removing harbor-ui ... done
Removing harbor-db ... done
Removing registry ... done
Removing harbor-adminserver ... done
Removing harbor-log ... done
Removing network harbor_harbor

# ./prepare
Clearing the configuration file: ./common/config/nginx/nginx.conf
Clearing the configuration file: ./common/config/ui/env
Clearing the configuration file: ./common/config/ui/app.conf
Clearing the configuration file: ./common/config/ui/private_key.pem
Clearing the configuration file: ./common/config/adminserver/env
Clearing the configuration file: ./common/config/jobservice/env
Clearing the configuration file: ./common/config/jobservice/app.conf
Clearing the configuration file: ./common/config/db/env
Clearing the configuration file: ./common/config/registry/config.yml
Clearing the configuration file: ./common/config/registry/root.crt
loaded secret from file: /mnt/cephfs/harbor/data/secretkey
Generated configuration file: ./common/config/nginx/nginx.conf
Generated configuration file: ./common/config/adminserver/env
Generated configuration file: ./common/config/ui/env
Generated configuration file: ./common/config/registry/config.yml
Generated configuration file: ./common/config/db/env
Generated configuration file: ./common/config/jobservice/env
Generated configuration file: ./common/config/jobservice/app.conf
Generated configuration file: ./common/config/ui/app.conf
Generated certificate, key file: ./common/config/ui/private_key.pem, cert file: ./common/config/registry/root.crt
The configuration files are ready, please use docker-compose to start the service.

# docker-compose up -d

Creating network "harbor_harbor" with the default driver
Creating harbor-log
Creating harbor-adminserver
Creating registry
Creating harbor-db
Creating harbor-ui
Creating harbor-jobservice
Creating nginx

我们可以通过docker-compose ps命令查看harbor组件的状态:

# docker-compose ps
       Name                     Command               State                                 Ports
--------------------------------------------------------------------------------------------------------------------------------
harbor-adminserver   /harbor/harbor_adminserver       Up
harbor-db            docker-entrypoint.sh mysqld      Up      3306/tcp
harbor-jobservice    /harbor/harbor_jobservice        Up
harbor-log           /bin/sh -c crond && rm -f  ...   Up      127.0.0.1:1514->514/tcp
harbor-ui            /harbor/harbor_ui                Up
nginx                nginx -g daemon off;             Up      0.0.0.0:443->443/tcp, 0.0.0.0:4443->4443/tcp, 0.0.0.0:8060->80/tcp
registry             /entrypoint.sh serve /etc/ ...   Up      5000/tcp

如果安全组将8060端口打开,通过访问:http://node_public_ip:8060,你将看到如下harbor的web页面:

img{512x368}

我们可以通过harbor内置的默认用户名和密码admin/Harbor12345登录harbor ui。当然,我们更重要的是通过cmdline访问harbor,push和pull image。如果这时你直接尝试docker login harbor_url,你可能会得到如下错误日志:

# docker login -u admin -p Harbor12345 node_public_ip:8060
Error response from daemon: Get https://node_public_ip:8060/v1/users/: http: server gave HTTP response to HTTPS client

这是因为docker默认采用https访问registry,因此我们需要在docker engine的配置中,添加–insecure-registry option。关于ubuntu 16.04下docker配置的问题,请参考这里

DOCKER_OPTS="--dns 8.8.8.8 --dns 8.8.4.4 --registry-mirror=https://xxxxx.mirror.aliyuncs.com --insecure-registry=node_public_ip:8060"

重启docker engine后尝试再次登录harbor:

docker login -u admin -p Harbor12345 node_public_ip:8060
Login Succeeded

一旦docker client login ok,我们就可以通过docker client对harbor中的相关repository进行操作了。

四、挂载路径修改

默认情况下,harbor将数据volume挂载到主机的/data路径下面。但由于我们采用ceph共享存储保证数据的高可用,需要修改harbor组件内容器的挂载路径,将其mount到共享存储挂载node上的路径:/mnt/cephfs/harbor/data/。对比两个路径,可以看出前缀由”/”变为了”/mnt/cephfs/harbor/”,我们需要修改docker-compose.yml和harbor.cfg两个文件。

由于docker-compose.yml文件较长,这里将原始文件改名为docker-compose.yml.orig,并将其与修改后的docker-compose.yml做对比:

# diff  docker-compose.yml.orig docker-compose.yml
8c8
<       - /var/log/harbor/:/var/log/docker/:z
---
>       - /mnt/cephfs/harbor/log/:/var/log/docker/:z
20c20
<       - /data/registry:/storage:z
---
>       - /mnt/cephfs/harbor/data/registry:/storage:z
40c40
<       - /data/database:/var/lib/mysql:z
---
>       - /mnt/cephfs/harbor/data/database:/var/lib/mysql:z
59,61c59,61
<       - /data/config/:/etc/adminserver/config/:z
<       - /data/secretkey:/etc/adminserver/key:z
<       - /data/:/data/:z
---
>       - /mnt/cephfs/harbor/data/config/:/etc/adminserver/config/:z
>       - /mnt/cephfs/harbor/data/secretkey:/etc/adminserver/key:z
>       - /mnt/cephfs/harbor/data/:/data/:z
80,81c80,81
<       - /data/secretkey:/etc/ui/key:z
<       - /data/ca_download/:/etc/ui/ca/:z
---
>       - /mnt/cephfs/harbor/data/secretkey:/etc/ui/key:z
>       - /mnt/cephfs/harbor/data/ca_download/:/etc/ui/ca/:z
100c100
<       - /data/job_logs:/var/log/jobs:z
---
>       - /mnt/cephfs/harbor/data/job_logs:/var/log/jobs:z
102c102
<       - /data/secretkey:/etc/jobservice/key:z
---
>       - /mnt/cephfs/harbor/data/secretkey:/etc/jobservice/key:z

harbor.cfg文件需要修改的地方不多:

// harbor.cfg

#The path of cert and key files for nginx, they are applied only the protocol is set to https
ssl_cert = /mnt/cephfs/harbor/data/cert/server.crt
ssl_cert_key = /mnt/cephfs/harbor/data/cert/server.key

#The path of secretkey storage
secretkey_path = /mnt/cephfs/harbor/data

配置修改完毕后,执行如下命令:

# docker-compose down -v
# prepare
# docker-compose up -d

新的harbor实例就启动起来了。注意:这一步我们用cephfs替换了本地存储,主要的存储变动针对log、database和registry三个输出数据的组件。你也许会感受到cephfs给harbor ui页面加载带来的影响,实感要比之前的加载慢一些。

五、使用外部数据库(external database)

前面提到了挂载ceph后,多个node上harbor实例中的db组件将出现竞争问题,导致只有一个node上的harbor db组件可以工作。因此,我们要使用外部数据库(或db集群)来解决这个问题。但是harbor官方针对如何配置使用外部DB很是“讳莫如深”,我们只能自己探索。

假设我们已经有了一个external database,并且建立了harbor这个user,并做了相应的授权。由于harbor习惯了独享database,在测试环境下可以考虑

GRANT ALL ON *.* TO 'harbor'@'%';

1、迁移数据

如果此时镜像库中已经有了数据,我们需要做一些迁移工作。

attach到harbor db组件的container中,将registry这张表dump到registry.dump文件中:

#docker exec -i -t  6e1e4b576315  bash

在db container中:
# mysqldump -u root -p --databases registry > registry.dump

回到node,将dump文件从container中copy出来:

#docker cp 6e1e4b576315:/root/registry.dump ./

再mysql login到external Database,将registry.dump文件导入:

# mysql -h external_db_ip -P 3306 -u harbor -p
# mysql> source ./registry.dump;

2、修改harbor配置,使得ui、jobservice组件连接external db

根据当前harbor architecture图所示:

img{512x368}

与database“有染”的组件包括ui和jobservice,如何通过配置修改来让这两个组件放弃老db,访问新的external db呢?这要从挖掘配置开始。harbor的组件配置都在common/config下:

~/harbor-install/harbor# tree -L 3 common
common
├── config
│   ├── adminserver
│   │   └── env
│   ├── db
│   │   └── env
│   ├── jobservice
│   │   ├── app.conf
│   │   └── env
│   ├── nginx
│   │   └── nginx.conf
│   ├── registry
│   │   ├── config.yml
│   │   └── root.crt
│   └── ui
│       ├── app.conf
│       ├── env
│       └── private_key.pem
└── templates
 ... ...

在修改config之前,我们先docker-compose down掉harbor。接下来,我们看到ui和jobservice下都有env文件,这里想必就是可以注入新db的相关访问信息的地方,我们来试试!

// common/config/ui/env
LOG_LEVEL=debug
CONFIG_PATH=/etc/ui/app.conf
UI_SECRET=$ui_secret
JOBSERVICE_SECRET=$jobservice_secret
GODEBUG=netdns=cgo
MYSQL_HOST=new_db_ip
MYSQL_PORT=3306
MYSQL_USR=harbor
MYSQL_PWD=harbor_password

// common/config/jobservice/env
LOG_LEVEL=debug
CONFIG_PATH=/etc/jobservice/app.conf
UI_SECRET=$ui_secret
JOBSERVICE_SECRET=$jobservice_secret
GODEBUG=netdns=cgo
MYSQL_HOST=new_db_ip
MYSQL_PORT=3306
MYSQL_USR=harbor
MYSQL_PWD=harbor_password

同时,由于不再需要harbor_db组件,因此切记:要将其从docker-compose.yml中剔除!。docker-compose up -d重新创建harbor各组件容器并启动!Harbor的日志可以在挂载的ceph路径: /mnt/cephfs/harbor/log下查找到:

/mnt/cephfs/harbor/log# tree 2017-06-09
2017-06-09
├── adminserver.log
├── anacron.log
├── CROND.log
├── jobservice.log
├── mysql.log
├── proxy.log
├── registry.log
├── run-parts.log
└── ui.log

我们以ui.log为例,我们发现harbor启动后,ui.log输出如下错误日志(jobservice.log也是相同):

Jun  9 11:00:17 172.19.0.1 ui[16039]: 2017-06-09T03:00:17Z [INFO] initializing database: type-MySQL host-mysql port-3306 user-root database-registry
Jun  9 11:00:18 172.19.0.1 ui[16039]: 2017-06-09T03:00:18Z [ERROR] [utils.go:94]: failed to connect to tcp://mysql:3306, retry after 2 seconds :dial tcp: lookup mysql: no such host

我们明明注入了新的db env,为何ui还是要访问“tcp://mysql:3306”呢?我们docker inspect一下ui的container,看看env是否包含我们添加的那些:

# docker inspect e91ab20e1dcb
... ...
            "Env": [
                "DATABASE_TYPE=mysql",
                "MYSQL_HOST=database_ip",
                "MYSQL_PORT=3306",
                "MYSQL_PWD=harbor_password",
                "MYSQL_USR=harbor",
                "MYSQL_DATABASE=registry",
            ],
.... ...

env已经注入,那么为何ui、jobservice无法连接到external database呢?要想搞清楚这点,我们只能去“啃代码”了。还好harbor代码并非很难啃。我们发现基于beego实现的ui、jobservice两个组件并未直接通过os.Getenv去获取这些env变量,而是调用了adminserver组件的服务。adminserver在初始化时,在RESET环境变量为true的情况下,读取了common/config/adminserver/env下的所有环境变量。

搞清楚原理后,我们知道了要修改的是common/config/adminserver/env,而不是common/config/ui/env和common/config/jobservice/env。我们将后两个文件还原。修改common/config/adminserver/env文件:

//common/config/adminserver/env
... ...
MYSQL_HOST=new_db_ip
MYSQL_PORT=3306
MYSQL_USR=harbor
MYSQL_PWD=harbor_password
... ...
RESET=true    <--- 改为true,非常关键

重新up harbor服务后,我们发现ui, jobservice与新database的连接成功了!打开harbor web页面,登录进去,我们看到了之前已经添加的用户、项目和镜像文件。

3、一劳永逸

如果你重新执行prepare,那么上面对config目录下的配置修改将被重新覆盖。如果要一劳永逸,那么需要修改的是common/templates下面的同位置同名配置文件。

六、安装其他节点上的harbor实例

前面,我们只搭建了一个节点,为的是验证方案的可行性。要实现高可用,我们还需要在其他节点上安装harbor实例。由于多个节点上harbor实例共同挂载ceph的同一目录,因此考虑到log的分离,在部署其他节点上的harbor时,最好对docker-compose.yml下log组件的volumes映射路径进行调整,以在多个节点间做隔离,便于日志查看,比如:

volumes:
      - /mnt/cephfs/harbor/log1/:/var/log/docker/:z

除此之外,各个节点上的harbor配置与上述配置完全一致。

七、共享session设置

到harbor的请求被负载均衡分发到多个node上的harbor实例上,这样就有了session共享的需求。Harbor对此已经给予了支持。在ui组件的代码中,我们发现ui在初始化时使用Getenv获取”_REDIS_URL”这个环境变量的值,因此我们只需要将_REDIS_URL这个环境变量配置到各个节点harbor ui组件的env文件中即可:

// common/config/adminserver/env

LOG_LEVEL=debug
CONFIG_PATH=/etc/ui/app.conf
UI_SECRET=LuAwkKUtYjF4l0mQ
JOBSERVICE_SECRET=SmsO1kVo4SrmgOIp
GODEBUG=netdns=cgo
_REDIS_URL=redis_ip:6379,100,redis_password,0

重新up harbor后,session共享生效。

不过光有一个外部redis存储共享session还不够,请求在多个harbor实例中的registry组件中进行鉴权需要harbor各个实例share相同的key和certificate。好在,我们的多harbor实例通过ceph共享存储,key和cert本就是共享的,都存放在目录:/mnt/cephfs/harbor/data/cert/的下边,因此也就不需要在各个harbor实例间同步key和cert了。

八、更换为域名访问

我们有通过域名访问docker registry的需求,那么直接通过域名访问harbor ui和registry是否可行呢?这要看harbor nginx的配置:

# docker ps |grep nginx
fa92765e8871        vmware/nginx:1.11.5-patched   "nginx -g 'daemon off"   3 hours ago
Up 3 hours          0.0.0.0:443->443/tcp, 0.0.0.0:4443->4443/tcp, 0.0.0.0:8060->80/tcp               nginx

# docker exec fa92765e8871 cat /etc/nginx/nginx.conf

... ...
http {
   server {
    listen 80;
   ... ...

}

nginx在http server block并未对域名或ip进行匹配,因此直接将域名A地址设置为反向代理的地址或直接解析为Harbor暴露的公网ip地址都是可以正常访问harbor服务的,当然也包括image push和pull服务。

注意:如果使用域名访问harbor服务,那么就将harbor.cfg中的hostname赋值为你的”域名+端口”,并重新prepare。否则你可能会发现通过harbor域名上传的image无法pull,因为其pull的地址为由ip组成的地址,以docker push hub.tonybai.com:8989/myrepo/foo:latest为例,push成功后,docker pull hub.tonybai.com:8989/myrepo/foo:latest可能提示你找不到该image,因为harbor中该imag
e的地址可能是my_ip_address:8989/myrepo/foo:latest。

九、统一registry的证书和token service的私钥

这是在本篇文章发表之后发现的问题,针对该问题,我专门写了一篇文章:《解决登录Harbor Registry时鉴权失败的问题》,请移步这篇文章,完成HA Harbor的搭建。

十、参考资料


微博:@tonybai_cn
微信公众号:iamtonybai
github.com: https://github.com/bigwhite

专访稿:兴趣才是第一生产力

本文是公司“运营拍档”公众号的专访文稿,这里转载一下^0^。原文链接在这里

十年生死两茫茫,白天忙,晚上忙,写程序,到天亮。千行代码,Bug何处藏。纵使上线又怎样,朝令改,夕断肠……


img{512x368}

白 明

东软云科技架构师
2017年Gopher China大会讲师
《七周七语言》译者之一
拥有10年编程工作经验
多年电信领域产品研发和技术管理经验
目前主要研究领域包括:
Go、Kubernetes、Docker和儿童编程教育等

一直以来,大家对程序员的固有印象是什么?刻板低调游戏宅?钱多话少无情趣?还是格子衬衫双肩包?无论哪种印象,都是对这个群体最偏激的总结,就像没见过海,总以为海是蔚蓝的。

一百位程序员有一百种样子,如果非要给程序员群体划分出派系,那白大师非禁欲系莫属。

img{512x368}

话少有内涵,明明帅到颠倒众生,却高冷禁欲不屑一顾

Go语言 – 未来企业级软件领域第一语言

就在上周,2017年Gopher China大会结束后,我们趁机“抓”住了被大会邀请担任讲师的白大师。希望能从这位颜值高、品味高、气质高的“三高”程序员身上,了解一些Gopher China这个“神秘组织”的信息。

img{512x368}

Q:上周被邀请作为2017年Gopher China大会的讲师,能向我们简单介绍一下Gopher China的江湖地位吗?

A:Gopher China是中国大陆地区规模最大,也是最具影响力的Go语言技术大会。这个大会从2015年开始举办,今年已经是第三届了,其影响力已经扩展到了港澳台和东南亚地区。今年在大会上就有一些来自宝岛台湾、中国香港以及东南亚地区的Gopher。Gopher在Go圈里专指Go程序员,因为Go语言的吉祥物是Gopher(地鼠)。

img{512x368}
 
另外,关于Go语言这门开源编程语言未来的发展,白大师也给出来了自己的看法。

“Go语言在中国大陆受欢迎程度非常高,甚至超出了全球平均水平。目前很火热的区块链技术的底层基础框架和平台很多也是由Go语言实现的,比如:以太坊。个人认为Go语言在未来发展前景一片光明,更有取代Java语言成为企业级软件领域第一语言的势头。”

兴趣才是第一生产力

像汤姆汉克斯为表演而生,恰克·帕拉尼克为写作而生一样,白大师为代码而生。他们这群人是天生的创造者,具有强烈的好奇心,且能把兴趣转化成终生事业。

img{512x368}

Q:是 什么原因让你决定从事编程工作?

A: “兴趣。”

Q:您觉得对于一位软件工程师来说,最重要的特质是什么?

A:“热爱编程。”

在外行人看起来枯燥无味的代码,对他们来说也是满屏的成就感。

“编程工作是为数不多的创造性智力劳动,未来世界编程将会变成普通公民的基本技能和能力,就像现在的语文、数学、物理、化学一样。”

都说“知识改变人生”,但现实往往是“兴趣改变人生”。如果说动力是一个人坚持下去的力量,那兴趣就是为动力提供能量的永动机。而白大师的“编程十年”就是源于最初的兴趣以及兴趣产生的无限能量。

代码外的世界

一位优秀的人之所以能称为优秀,最重要的原因就是你能从他身上不断寻找到惊喜。

img{512x368}

惊喜不断的白大师

当我以为白大师用了十年的时间钻研编程,沉浸在代码的世界里,他告诉我他也用了十年的时间写博客,现在仍孜孜不倦。

当我以为他只是用文字记录生活、消磨时间,他却告诉我自己也翻译过一本编程类的书,叫《七周七语言》。

img{512x368}

当我以为这些经历已足够填满他这十年的时间,他说自己还是个“绝对梅吹”。喜欢阿根廷队,关注阿根廷球星,尤其在2005年看到了天赋异禀的梅西后,就一直膜拜至今。

img{512x368}

白大师和他的那些经典理论

当然,白大师带给我的惊喜,远远不止于他的爱好,还有一些“经典理论”。

比如“年轻心态产生论”。

Q:“为什么会选择加入运营拍档技术团队呢?哪些地方吸引了您?“

A:“因为运营拍档技术团队所在的部门女同学平均年龄最低、平均颜值最高。在这样的环境下工作,心态都会变得年轻。这才是年轻心态产生的根本原因。
(说好的高冷禁欲系呢?)

比如,“挑战收获论”。

Q:“您之前参与翻译过《七周七语言》,为什么会去做这项工作?这样的经历给您带来哪些收获?“

A:“参与翻译工作,主要是想挑战一下自己。收获自然是有的,最大的收获是让我认识到翻译书这事儿真的很难,投入产出比很低。“

其实,兴趣不只是对事物表面的关心,任何一种兴趣都是由于获得这方面的知识或成就感使人的体验在情绪上得到满足而循环产生的。很多时候我们觉得,一旦将兴趣变成工作,它最单纯的本质就变了样。可事实上,白大师用自己的经历向我们证明了:兴趣,才是第一生产力。

img{512x368}


微博:@tonybai_cn
微信公众号:iamtonybai
github.com: https://github.com/bigwhite




这里是Tony Bai的个人Blog,欢迎访问、订阅和留言!订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:


以太币:


如果您喜欢通过微信App浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:



本站Powered by Digital Ocean VPS。

选择Digital Ocean VPS主机,即可获得10美元现金充值,可免费使用两个月哟!

著名主机提供商Linode 10$优惠码:linode10,在这里注册即可免费获得。

阿里云推荐码:1WFZ0V立享9折!

View Tony Bai's profile on LinkedIn


文章

评论

  • 正在加载...

分类

标签

归档











更多