搭建Docker私有倉庫

摘要

這篇文章內容包括搭建docker私有倉庫的一些配置項和遇到的問題及解決方案。html

1.配置項
1.1. 數據持久化
1.2. TLS 支持
1.3. 登陸受權驗證
1.4. docker compose
2. 測試
3. NGINX作代理
3.1. 個人方式和遇到的問題
3.2. NGINX 做爲一個容器
4. 其它方案
5. 相關連接

Docker官方提供了 registry鏡像, 能夠方便的搭建私有倉庫,詳細文檔參考這裏linux

配置項

數據持久化

能夠經過採用數據卷掛載或者直接掛載宿主機目錄的方式來進行。掛載到容器內默認位置: /var/lib/registry
好比能夠像以下方式啓動, 這裏將容器數據存儲在了 /mnt/registry.nginx

$ docker run -d \
  -p 5000:5000 \
  --restart=always \
  --name registry \
  -v /mnt/registry:/var/lib/registry \
  registry:2

固然,鏡像還提供了其它支持的存儲方式,好比OSS等。git

官方文檔參見這裏github

TLS 支持

爲了使得私有倉庫安全地對外開放,須要配置 TLS 支持。web

測試的時候,若是不配置的話TLS,能夠在docker客戶端中的 "insecure registry" 裏添加私有倉庫地址,否則默認的都以安全的tsl方式來訪問私有倉庫,具體更改方式能夠參考這裏docker

個人CA證書是從阿里雲獲取的(由於域名是在上面註冊的,能夠提供免費的證書,雖然若是作得很隱蔽)。apache

registry鏡像能夠經過 REGISTRY_HTTP_TLS_CERTIFICATEREGISTRY_HTTP_TLS_KEY 環境參數配置TLS支持。
例以下面這樣, domain.crtdomain.key 是得到的證書,另外配置容器監聽ssl默認的 443 端口。ubuntu

$ docker run -d \
  --restart=always \
  --name registry \
  -v `pwd`/certs:/certs \
  -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
  -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
  -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
  -p 443:443 \
  registry:2

官方文檔參見這裏api

登陸受權驗證

能夠經過 htpasswd 來配置簡單的authentication (注意:驗證須要 TLS 支持)。

首先在 auth 目錄下經過reistry裏的 htpasswd 工具建立 驗證文件 auth/htpasswd

$ mkdir auth
$ docker run \
  --entrypoint htpasswd \
  registry:2 -Bbn testuser testpassword > auth/htpasswd

啓動的時候經過 REGISTRY_AUTH, REGISTRY_AUTH_HTPASSWD_REALM, REGISTRY_AUTH_HTPASSWD_PATH 來配置:

$ docker run -d \
  -p 5000:5000 \
  --restart=always \
  --name registry \
  -v `pwd`/auth:/auth \
  -e "REGISTRY_AUTH=htpasswd" \
  -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
  -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
  -v `pwd`/certs:/certs \
  -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
  -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
  registry:2

這樣就啓動了一個監聽5000端口的、支持TLS和簡單登陸驗證的docker 私有倉庫。

官方文檔參見這裏

docker compose

"docker compose" 是一個方便定義和運行多個容器的工具, 安裝參見這裏, 或者經過pip安裝: pip install docker-compose

以上配置項經過 docker compose 的方式組織起來以下:

文件命名成 docker-compose.yaml

registry:
  restart: always
  image: registry:2
  ports:
    - 5000:5000
  environment:
    REGISTRY_HTTP_TLS_CERTIFICATE: /certs/domain.crt
    REGISTRY_HTTP_TLS_KEY: /certs/domain.key
    REGISTRY_AUTH: htpasswd
    REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
    REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
  volumes:
    - /path/data:/var/lib/registry
    - /path/certs:/certs
    - /path/auth:/auth

docker-compose.yaml 所在目錄運行:

docker-compose up

測試

私有倉庫搭建好了如何測試?

# 先拉取官方鏡像
$ docker pull ubuntu:16.04

# 打上標籤
$ docker tag ubuntu:16.04 myregistrydomain.com/my-ubuntu

# 推到私有倉庫
$ docker push myregistrydomain.com/my-ubuntu

# 從私有倉庫獲取
$ docker pull myregistrydomain.com/my-ubuntu

Nginx作代理

個人方式和遇到的問題

實際配置中,我採用了 nginx 做爲代理,來訪問 registry服務。我將TLS支持和登陸驗證都加到了nginx一層。

nginx 配置文件:

upstream docker-registry {
  server localhost:5000;                          # !轉發到registry 監聽的5000 端口!
}

## Set a variable to help us decide if we need to add the
## 'Docker-Distribution-Api-Version' header.
## The registry always sets this header.
## In the case of nginx performing auth, the header is unset
## since nginx is auth-ing before proxying.
map $upstream_http_docker_distribution_api_version $docker_distribution_api_version {
  '' 'registry/2.0';
}

server {
  listen 443 ssl;
  server_name domain.com;  # !這裏配置域名!

  # SSL
  ssl_certificate /path/to/domain.pem;               # !這裏配置CA 證書信息!
  ssl_certificate_key /path/to/domain.key;           # !這裏配置CA 證書信息!

  # Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
  ssl_protocols TLSv1.1 TLSv1.2;
  ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
  ssl_prefer_server_ciphers on;
  ssl_session_cache shared:SSL:10m;

  # disable any limits to avoid HTTP 413 for large image uploads
  client_max_body_size 0;

  # required to avoid HTTP 411: see Issue #1486 (https://github.com/moby/moby/issues/1486)
  chunked_transfer_encoding on;

  location /v2/ {
    # Do not allow connections from docker 1.5 and earlier
    # docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents
    if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" ) {
      return 404;
    }

    # To add basic authentication to v2 use auth_basic setting.
    auth_basic "Registry realm";
    auth_basic_user_file /path/to/auth/htpasswd;          # !這裏配置auth文件位置!

    ## If $docker_distribution_api_version is empty, the header is not added.
    ## See the map directive above where this variable is defined.
    add_header 'Docker-Distribution-Api-Version' $docker_distribution_api_version always;

    proxy_pass                          http://docker-registry;
    proxy_set_header  Host              $http_host;   # required for docker client's sake
    proxy_set_header  X-Real-IP         $remote_addr; # pass on real client's IP
    proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header  X-Forwarded-Proto $scheme;
    proxy_read_timeout                  900;
  }
}

其中 /path/to/auth/htpasswd 文件是經過 registry 中的或者本地的 htpasswd 工具生成的

$ docker run \
  --entrypoint htpasswd \
  registry:2 -Bbn testuser testpassword > auth/htpasswd

registry的 docker-compose 文件:

version: '2'
services:
  my_registry:
    restart: always
    image: registry:2
    ports:
      - 127.0.0.1:5000:5000
    volumes:
      - ./data:/var/lib/registry

啓動後,當我從本地視圖login到私有倉庫時,發生錯誤:

➜  ~ docker login domain.com
Username: testuser
Password:
Error response from daemon: login attempt to https://hub.docker.equiz.cn/v2/ failed with status: 500 Internal Server Error

查看日誌發現nginx 錯誤日誌裏有個編碼相關的錯誤:

# nginx error log

*4 crypt_r() failed (22: Invalid argument)

通過一番研究,發現以前加密時,是採用 Bcrypt 加密方式,看下 htpasswd 的使用說明:

root@data1:~# htpasswd
Usage:
        htpasswd [-cimBdpsDv] [-C cost] passwordfile username
        htpasswd -b[cmBdpsDv] [-C cost] passwordfile username password

        htpasswd -n[imBdps] [-C cost] username
        htpasswd -nb[mBdps] [-C cost] username password
 -c  Create a new file.
 -n  Don't update file; display results on stdout.
 -b  Use the password from the command line rather than prompting for it.
 -i  Read password from stdin without verification (for script usage).
 -m  Force MD5 encryption of the password (default).
 -B  Force bcrypt encryption of the password (very secure).
 -C  Set the computing time used for the bcrypt algorithm
     (higher is more secure but slower, default: 5, valid: 4 to 31).
 -d  Force CRYPT encryption of the password (8 chars max, insecure).
 -s  Force SHA encryption of the password (insecure).
 -p  Do not encrypt the password (plaintext, insecure).
 -D  Delete the specified user.
 -v  Verify password for the specified user.
On other systems than Windows and NetWare the '-p' flag will probably not work.
The SHA algorithm does not use a salt and is less secure than the MD5 algorithm.

能夠看到 -B 會使用 bcrypt 的方式來加密,nginx默認不支持。至於如何讓nginx支持bcrypt我暫時還未找到方案,留待之後研究了(TODO)

簡單的解決方式是換成默認的MD5加密(由於安全等級問題又不推薦不用bcrypt方式的),

docker run --rm --entrypoint htpasswd registry:2 -bn testuser testpassword > auth/htpasswd   # 這裏少了 -B 選項

關於 bcrypt 加密方式,這裏 有一篇不錯的文章介紹。不過好像對於這個加密方式,網上有一些爭論,我就不詳究了。

不依賴 "apche tools" 的 nginx 加密方式參考 這裏, 好比MD5加密:

printf "testuser:$(openssl passwd -1 testpassword)\n" >> .htpasswd # this example uses MD5 encryption

Nginx 做爲一個容器

docker 文檔也有如何採用nginx容器和registry配合使用的說明,參考這裏

"docker-compose.yaml" 以下:

nginx:
  # Note : Only nginx:alpine supports bcrypt.
  # If you don't need to use bcrypt, you can use a different tag.
  # Ref. https://github.com/nginxinc/docker-nginx/issues/29
  image: "nginx:alpine"     # !這裏必定要採用alpine鏡像,由於它裏的nginx支持 bcrypt 加密!
  ports:
    - 5043:443
  links:
    - registry:registry
  volumes:
    - ./auth:/etc/nginx/conf.d
    - ./auth/nginx.conf:/etc/nginx/nginx.conf:ro

registry:
  image: registry:2
  ports:
    - 127.0.0.1:5000:5000
  volumes:
    - ./data:/var/lib/registry

這裏nginx容器監聽的是5043, 因此使用的私有倉庫的地址變成了 registrydomain.com:5043,
我不喜歡後面加端口,但本機又存在其餘須要nginx監聽的443端口的服務(不一樣doamin下),因此不能讓nginx容器直接監聽443端口,故沒有采用這種方式。

另外在尋找解決方案的時候發現一個鏡像 nginx-proxy, 能夠方便地監聽新添加的容器,留待之後探索。

其它方案

或許你想用letsencrypts免費證書,不妨看看這個工具:acme.sh

或許你不知足的簡易方案,你可能還須要web界面來方便查看和管理你的鏡像倉庫,那麼你能夠查看下企業級的容器倉庫方案: vmware/harbor

相關連接

相關文章
相關標籤/搜索