Edited at

快適な kubernetes オンプレミス環境を構築する(8. プライベートレジストリを構築する)

More than 1 year has passed since last update.


シリーズ目次


  1. 設計編

  2. RancherOSインストール & セットアップ

  3. Rancher Server のセットアップ

  4. Kubernetes環境にホストを追加する

  5. nginx-ingress-controllerを使ったIngress環境のセットアップ

  6. SSL自動発行環境セットアップ(kube-lego)

  7. NFSサーバ&NFSクライアントセットアップ

  8. プライベートレジストリを構築する

  9. 総括


プライベートレジストリを構築する


  • Portus と docker registry を使ってプライベートレジストリを構築していきます

  • Portus は docker registry のレポジトリビューと認証などを担当してくれるツールです


    • 今回は Portus の認証に OpenLDAP を使います



  • Portus 単体では docker イメージを保存してくれるわけではないのでご注意ください


今回の記事の注意点


  • 今回の説明は大変不親切です。yaml のみの提示になってしまい申し訳ないです(´・ω・`)


    • 提示した yaml は、すべて kubectl create コマンドでデプロイを行っています



  • Portus と Docker registry 間で認証の通信が発生します
    * 証明書をリポジトリのクライアント認証に使用 の記載が詳しいです


    • その通信が発生する際に SSL 証明書が各々の Pod で必要になります

    • イメージとしては Ingress で発行した SSL 証明書をマウントして、Portus と Docker Registry の Pod にマウントして使います




構築するサービス

サービス名
URL

Portus
portus.k8s.example.com

Docker Registry
cr.k8s.example.com


  • (cr は Container Registry の略です)


ざっくりとした流れ


  • Portus で利用する DB を k8s 環境にデプロイ


    • 利用するストレージは前回構築した NFS ストレージを利用する



  • Portus を k8s 環境にデプロイ

  • Docker Registry を k8s 環境にデプロイ


Portus の構築


DB デプロイ


  • Portus で利用する DB をデプロイします

  • ここでは一気に Deployment/PVC/SVC をデプロイしています

apiVersion: extensions/v1beta1

kind: Deployment
metadata:
name: portus-mariadb
namespace: portus
spec:
replicas: 1
template:
metadata:
labels:
app: mariadb
spec:
containers:
- name: mariadb
image: mariadb:10.1.14
ports:
- name: mysql-port
containerPort: 3306
volumeMounts:
- mountPath: "/var/lib/mysql"
name: mariadb1-mount
env:
- name: MYSQL_ROOT_PASSWORD
value: "portus"
- name: MYSQL_DATABASE
value: "portus"
- name: MYSQL_USER
value: "portus"
- name: MYSQL_PASSWORD
value: "portus"

# timeoutSeconds: 1
volumes:
- name: mariadb1-mount
persistentVolumeClaim:
claimName: mariadb1-claim
---
apiVersion: "v1"
kind: "PersistentVolumeClaim"
metadata:
name: "mariadb1-claim"
annotations:
volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"
spec:
accessModes:
- "ReadWriteMany"
resources:
requests:
storage: "30Gi"
---
apiVersion: v1
kind: Service
metadata:
name: portus-mariadb
spec:
ports:
- name: mysql-port
port: 3306
# targetPort: 80
protocol: TCP
selector:
app: mariadb


Portus のデプロイ


  • Portus では LDAP 認証を利用することにします


Ingress


  • SSL 証明書の発行をまずはしておきたいため、 Ingress からデプロイします

apiVersion: extensions/v1beta1

kind: Ingress
metadata:
name: portus
annotations:
kubernetes.io/tls-acme: 'true'
spec:
rules:
- host: portus.k8s.example.com
http:
paths:
- path: /
backend:
serviceName: portus
servicePort: 3000
tls:
- hosts:
- "portus.k8s.example.com"
secretName: portus-kubernetes


ConfigMap

apiVersion: v1

kind: ConfigMap
metadata:
labels:
app: portus
name: portus
data:
config-local.yml: |
gravatar:
enabled: true
delete:
enabled: true
ldap:
enabled: true
hostname: <LDAP サーバのアドレス>
port: 636
method: "simple_tls"
# The base where users are located (e.g. "ou=users,dc=example,dc=com").
base: "ou=people,dc=example,dc=com"

# User filter (e.g. "mail=george*").
filter: "(objectClass=posixAccount)"

# The LDAP attribute where to search for username. The default is 'uid'.
uid: "mail"
guess_email:
enabled: true
attr: "mail"
first_user_admin:
enabled: true
# By default require ssl to be enabled when running on production
check_ssl_usage:
enabled: false

# Contains advanced options that tweak how Portus interacts with the
# Registry. Don't touch any of these values unless you *really* know what you
# are doing.
registry:
jwt_expiration_time:
value: 5
catalog_page:
value: 100
machine_fqdn:
value: "portus.k8s.example.com"
display_name:
enabled: false
user_permission:
change_visibility:
enabled: true
manage_team:
enabled: true
manage_namespace:
enabled: true


Secret


  • Secret を作成しておいて、後述する Deployment で利用します


DB 用の Secret ファイル

apiVersion: v1

kind: Secret
metadata:
name: portus-db
data:
# 先述した DB の名前などと設定を合わせてください
# DB の DB 名、ホスト名(サービス名)、パスワードなどを base64 化した値を入れます(改行は省いてください)
# cG9y ... という文字列は base64 デコードすると「portus」になります
db-name: cG9ydHVz
hostname: cG9ydHVz
password: cG9ydHVz
username: cG9ydHVz
type: Opaque


LDAP 用の Secret ファイル

apiVersion: v1

kind: Secret
metadata:
name: portus-ldap
type: Opaque
data:
# LDAP に接続する BindDN を base64 化した値を入れます(ここでは hoge という値が入っています)
bind-dn: aG9nZQ==
# LDAP に接続する BindPassword を base64 化した値を入れます(ここでは hoge という値が入っています)
bind-password: aG9nZQ==


Portus 用の Secret ファイル


  • Portus は Rails アプリなのですが、それに必要となる Secret 情報をここで定義します

apiVersion: v1

kind: Secret
metadata:
name: portus
data:
# base64 decode result = hoge
password: aG9nZQ==
# base64 decode result = hoge
secret-key-base: aG9nZQ==
type: Opaque


Deployment

apiVersion: extensions/v1beta1

kind: Deployment
metadata:
labels:
app: portus
name: portus
namespace: portus
spec:
replicas: 1
selector:
matchLabels:
app: portus
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
type: RollingUpdate
template:
metadata:
labels:
app: portus
spec:
containers:
- env:
- name: RAILS_ENV
value: production
- name: REGISTRY_SSL_ENABLED
value: "false"
- name: RAILS_SERVE_STATIC_FILES
value: "true"
- name: PORTUS_CHECK_SSL_USAGE_ENABLED
value: "false"
- name: REGISTRY_HOSTNAME
value: cr.k8s.example.com
- name: PORTUS_MACHINE_FQDN_VALUE
value: portus.k8s.example.com
- name: PORTUS_DEBUG
value: "true"
- name: PORTUS_LOCAL_CONFIG_PATH
value: /etc/portus/config/local/config-local.yml
- name: PORTUS_DB_HOST
valueFrom:
secretKeyRef:
key: hostname
name: portus-db
- name: PORTUS_DB_USERNAME
valueFrom:
secretKeyRef:
key: username
name: portus-db
- name: PORTUS_DB_PASSWORD
valueFrom:
secretKeyRef:
key: password
name: portus-db
- name: PORTUS_DB_DATABASE
valueFrom:
secretKeyRef:
key: db-name
name: portus-db
- name: PORTUS_PASSWORD
valueFrom:
secretKeyRef:
key: password
name: portus
- name: PORTUS_SECRET_KEY_BASE
valueFrom:
secretKeyRef:
key: secret-key-base
name: portus
- name: PORTUS_LDAP_AUTHENTICATION_ENABLED
value: "true"
- name: PORTUS_LDAP_AUTHENTICATION_BIND_DN
valueFrom:
secretKeyRef:
key: bind-dn
name: portus-ldap
- name: PORTUS_LDAP_AUTHENTICATION_PASSWORD
valueFrom:
secretKeyRef:
key: bind-password
name: portus-ldap
- name: PORTUS_KEY_PATH
value: /etc/ssl/portus/tls.key
- name: PUMA_TLS_KEY_PATH
value: /etc/ssl/portus/tls.key
- name: PUMA_TLS_CERT_BUNDLE_PATH
value: /etc/ssl/portus/tls.crt
image: opensuse/portus:2.3
imagePullPolicy: IfNotPresent
name: portus
ports:
- containerPort: 3000
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /
port: 3000
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources: {}
volumeMounts:
- mountPath: /etc/ssl/portus
name: certificates
readOnly: true
- mountPath: /etc/portus/config/local
name: config
readOnly: true
- env:
- name: PORTUS_BACKGROUND
value: "true"
- name: CCONFIG_PREFIX
value: PORTUS
- name: PORTUS_MACHINE_FQDN_VALUE
value: portus.k8s.example.com
- name: REGISTRY_SSL_ENABLED
value: "false"
- name: PORTUS_DB_HOST
valueFrom:
secretKeyRef:
key: hostname
name: portus-db
- name: PORTUS_DB_USERNAME
valueFrom:
secretKeyRef:
key: username
name: portus-db
- name: PORTUS_DB_PASSWORD
valueFrom:
secretKeyRef:
key: password
name: portus-db
- name: PORTUS_DB_DATABASE
valueFrom:
secretKeyRef:
key: db-name
name: portus-db
- name: PORTUS_KEY_PATH
value: /etc/ssl/portus/tls.key
- name: PORTUS_PASSWORD
valueFrom:
secretKeyRef:
key: password
name: portus
- name: PORTUS_SECRET_KEY_BASE
valueFrom:
secretKeyRef:
key: secret-key-base
name: portus
- name: PORTUS_LOG_LEVEL
value: debug
image: opensuse/portus:2.3
imagePullPolicy: IfNotPresent
name: portus-background
resources: {}
volumeMounts:
- mountPath: /etc/ssl/portus
name: certificates
readOnly: true
- mountPath: /etc/portus/config/local
name: config
readOnly: true
volumes:
- name: certificates
secret:
defaultMode: 420
secretName: portus-kubernetes
- name: portus-ldap
secret:
defaultMode: 440
secretName: portus-ldap
- configMap:
defaultMode: 440
name: portus
name: config


Service

apiVersion: v1

kind: Service
metadata:
name: portus
labels:
app: portus
spec:
ports:
- name: http
port: 3000
targetPort: 3000
selector:
app: portus


docker-reigstry の構築


Ingress


  • こちらも Ingress を先に定義しておき、SSL 証明書の発行をしておきます

apiVersion: extensions/v1beta1

kind: Ingress
metadata:
name: cr
annotations:
kubernetes.io/tls-acme: 'true'
nginx.ingress.kubernetes.io/proxy-body-size: 900m
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
spec:
rules:
- host: cr.k8s.exaple.com
http:
paths:
- path: /
backend:
serviceName: portus-registry
servicePort: 5000
tls:
- hosts:
- "cr.k8s.example.com"
secretName: cr-kubernetes


ConfigMap

apiVersion: v1

kind: ConfigMap
metadata:
labels:
app: portus-registry
name: portus-registry
data:
init: |-
#!/bin/sh
registry serve /etc/docker/registry/config.yml
config.yml: |-
version: 0.1
logLevel: debug
storage:
filesystem:
rootdirectory: /registry-data
delete:
enabled: true
http:
addr: 0.0.0.0:5000
debug:
addr: 0.0.0.0:5001
auth:
token:
realm: https://cr.k8s.example.com/v2/token
service: cr.k8s.example.com
issuer: portus.k8s.example.com
rootcertbundle: /certificates/tls.crt
notifications:
endpoints:
- name: portus
url: https://cr.k8s.example.com/v2/webhooks/events
timeout: 500ms
threshold: 5
backoff: 1s


PVC

kind: PersistentVolumeClaim

apiVersion: v1
metadata:
name: portus-registry-claim
annotations:
volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"
labels:
storage: registry
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 100Gi


Deployment

apiVersion: extensions/v1beta1

kind: Deployment
metadata:
name: portus-registry
spec:
replicas: 1
template:
metadata:
labels:
app: registry
tier: registry
spec:
containers:
- name: registry
image: library/registry:2.6
command: ["/bin/sh", "/etc/docker/registry/init"]
imagePullPolicy: IfNotPresent
resources:
requests:
cpu: 100m
memory: 200Mi
ports:
- containerPort: 443
- containerPort: 5001
volumeMounts:
- name: registry-configmap
mountPath: /etc/docker/registry
readOnly: true
- name: certificates
mountPath: /certificates
readOnly: true
- name: portus-registry-storage
mountPath: /registry-data
volumes:
- name: certificates
secret:
secretName: cr-kubernetes
- name: portus-registry-storage
persistentVolumeClaim:
claimName: portus-registry-claim
- configMap:
defaultMode: 440
name: portus-registry
name: registry-configmap


Service

apiVersion: v1

kind: Service
metadata:
name: portus-registry
labels:
app: registry
tier: registry
spec:
ports:
- port: 5000
targetPort: 5000
selector:
app: registry
tier: registry


動作確認



  • portus.k8s.exmaple.com で構築した場合、 https://portus.k8s.example.com/ にアクセスできるか確認してみる

  • docker login/docker push/docker pull できるか確認する

# ログインできるか試す

$ docker login https://cr.k8s.example.com/
(LDAP アカウントでログインできるか確認する)

# DockerHub から hello-world イメージを取得
$ docker run hell-world

# hello-world image を元にタグをつける
$ docker tag hello-world cr.k8s.example.com/kaishuu0123/hello

# cr.k8s.exaple.com に docker push
$ docker push cr.k8s.example.com/kaishuu0123/hello

# イメージがない VM などで pull できるか試す
$ docker login https://cr.k8s.example.com/
$ docker pull cr.k8s.example.com/kaishuu0123/hello


まとめ


  • プライベートレジストリを作りました

  • これで Dockerhub を経由しなくてもイメージをオンプレの環境に保存しておくことができますね