04 02 install registry - kropachev/1c-devops-jr GitHub Wiki
Установка Docker Registry
Для работы пайплайна нам понадобятся образы агентов 1C, которые будут запускаться внутри кластера k3s. По лицензионным ограничениям образы 1С, содержащие платформу 1С или связанные с ней компоненты нельзя распространять публично. Это значит мы не можем создать образ и загрузить его в публичный докерхаб. Решением будет локальный Docker Registry.
Разворачиваем Docker Registry в k3s с доступом по HTTPS, аутентификацией и постоянным хранилищем данных.
Мы получим:
- Доступ по имени
registry.onecci.lan - HTTPS с сертификатом (Kubernetes TLS Secret)
- Аутентификация по логину/паролю (basic auth через htpasswd)
- Данные образов в PersistentVolume (PVC)
Подготовка рабочей директории
Все манифесты и файлы будем хранить на сервере в одном месте.
mkdir -p /k3s-1c-ci/registry
cd /k3s-1c-ci/registry
Namespace
Создаем namespace
kubectl create namespace registry --dry-run=client -o yaml | kubectl apply -f -
Проверка:
kubectl get ns registry
Настройка доверия для containerd (k3s) при работе с registry
Для registry по HTTPS k3s/containerd должен знать, каким CA доверять.
Создаем (или дополняем) файл:
sudo nano /etc/rancher/k3s/registries.yaml
Добавляем конфигурацию (пример для registry.onecci.lan):
configs:
"registry.onecci.lan":
tls:
ca_file: /etc/ssl/certs/ca-certificates.crt
Применяем изменения (перечитывание конфигурации containerd):
sudo systemctl restart k3s
TLS Secret из сертификата
Команда создает Secret или обновляет, если, например, был перевыпущен сертификат:
kubectl create secret tls onecci.lan.tls \
--cert=/k3s-1c-ci/tls/tls.crt \
--key=/k3s-1c-ci/tls/tls.key \
-n registry \
--dry-run=client -o yaml | kubectl apply -f -
Проверяем:
kubectl get secret onecci.lan.tls -n registry
Создаем учетку доступа (basic auth)
Без аутентификации любой, кто видит адрес Registry, сможет пушить и вытягивать образы.
Генерируем bcrypt прямо в кластере, временным pod’ом.
registryusr- имя пользователя registryregistrypass- пароль;
kubectl -n registry run htpasswd-gen \
--image=httpd:2.4-alpine \
--restart=Never \
--command -- sh -c "htpasswd -Bbn registryusr registrypass"
Выводим результат в файл:
htpasswd- файл, в которых будет записана пара логин и пароль
kubectl -n registry logs htpasswd-gen > htpasswd
Удаляем pod:
kubectl -n registry delete pod htpasswd-gen
Проверяем:
head -n1 htpasswd
Создаем secret registry-auth:
kubectl -n registry create secret generic registry-auth \
--from-file=htpasswd=./htpasswd \
--dry-run=client -o yaml | kubectl apply -f -
Проверяем секрет
kubectl -n registry get secret registry-auth
Создаем конфигурацию Registry
Здесь мы включаем basic auth, задаем путь хранения образов, оставляем Registry слушать HTTP (TLS делает Traefik).
Создаем файл
nano registry-config.yml
Содержимое:
version: 0.1
log:
# просто метка сервиса в логах
fields:
service: registry
storage:
filesystem:
# где Registry хранит blobs и manifests
# это путь внутри контейнера, мы примонтируем сюда PVC
rootdirectory: /var/lib/registry
delete:
enabled: true
http:
# Registry слушает внутри кластера на 5000/tcp
addr: :5000
headers:
# базовая защита - запрещает браузеру угадывать content-type
X-Content-Type-Options:
- nosniff
auth:
htpasswd:
# имя realm, которое увидит клиент при запросе логина
realm: basic-realm
# путь к файлу htpasswd внутри контейнера
# мы примонтируем secret registry-auth в /auth
path: /auth/htpasswd
Создаем ConfigMap registry-config:
kubectl -n registry create configmap registry-config \
--from-file=config.yml=./registry-config.yml \
--dry-run=client -o yaml | kubectl apply -f -
Проверяем:
kubectl -n registry get configmap registry-config
Создаем PVC для данных Registry
Без PVC данные будут жить в контейнере и потеряются при пересоздании pod
Наш кластер состоит из одного узла и мы будем использовать local-path (k3s default) - данные на локальном диске ноды, просто и быстро.
При добавлении узлов или переходе в production логика PVC не меняется, меняется только StorageClass (например, NFS / Longhorn / Ceph).
PVC манифест (storage по умолчанию для одного узла)
Создаем pvc.yml:
nano pvc.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: registry-data
namespace: registry
spec:
# ReadWriteOnce - том монтируется на одну ноду и один pod
# для Registry (replicas: 1) это нормально
accessModes:
- ReadWriteOnce
# storageClassName можно указать явно.
# если не указывать - будет использован default StorageClass.
# storageClassName: local-path
resources:
requests:
# сколько места нужно под образы
storage: 20Gi
Пояснение по поводу значения storage: 20Gi - это сообщение этому pod можно использовать том размером до 20 GiB, место занимается фактически использованное, а не заявленное.
Применяем и проверяем:
kubectl apply -f pvc.yml
kubectl -n registry get pvc registry-data
Создаем Deployment и Service
Deployment описывает, как запускать pod Registry: какой образ, какие порты, какие переменные, какие тома и секреты подключить. Deployment следит, чтобы нужное число pod было запущено (у нас replicas: 1).
Service дает pod стабильный DNS-адрес и порт внутри кластера. Ingress (Traefik) направляет трафик в Service, а не в pod напрямую.
Probes - настройки проверок:
-
livenessProbe (живой ли контейнер) - Kubernetes перезапустит контейнер, если проверка долго не проходит.
-
readinessProbe (проверка готовности) - Kubernetes не будет отправлять трафик в pod, пока проверка не проходит.
Создаем файл
nano registry.yml
Содержимое файла:
apiVersion: apps/v1
kind: Deployment
metadata:
name: registry
namespace: registry
spec:
# Registry обычно запускается в 1 экземпляре, потому что стандартный filesystem storage
# не рассчитан на многоподовую работу без общего хранилища и блокировок.
replicas: 1
selector:
matchLabels:
app: registry
template:
metadata:
labels:
app: registry
spec:
containers:
- name: registry
image: registry:2
ports:
- containerPort: 5000
volumeMounts:
# данные Registry (PVC)
- name: data
mountPath: /var/lib/registry
# htpasswd из secret
- name: auth
mountPath: /auth
readOnly: true
# config.yml из ConfigMap
- name: config
mountPath: /etc/docker/registry
readOnly: true
livenessProbe:
tcpSocket:
port: 5000
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
tcpSocket:
port: 5000
initialDelaySeconds: 5
periodSeconds: 5
volumes:
- name: data
persistentVolumeClaim:
claimName: registry-data
- name: auth
secret:
secretName: registry-auth
- name: config
configMap:
name: registry-config
---
apiVersion: v1
kind: Service
metadata:
name: registry
namespace: registry
spec:
selector:
app: registry
ports:
- name: http
port: 5000
targetPort: 5000
Применяем:
kubectl apply -f registry.yml
Проверяем:
kubectl -n registry get deploy,po,svc
Настройка Ingress
Создаем файл настроек Ingress.
nano registry-ingress.yaml
Пример манифеста:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: registry
namespace: registry
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
spec:
ingressClassName: traefik
tls:
- secretName: onecci.lan.tls
hosts:
- registry.onecci.lan
rules:
- host: registry.onecci.lan
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: registry
port:
number: 5000
Применяем манифест и проверяем:
kubectl apply -f registry-ingress.yaml
kubectl -n registry get ingress
Шаг 9. Проверка доступа по HTTPS
С клиента:
curl -Ik https://registry.onecci.lan/v2/
Ожидаемые варианты:
401 Unauthorized- это нормально, значит TLS работает и Registry требует логин- ошибки TLS - значит клиент не доверяет сертификату (актуально для самоподписанных)