Приклад розгортання сервісу в віртуальному кластері
Встановлюємо K8up, який ми будемо використовувати для бекапів волюмів:
- Створюємо namespace
kubectl create ns k8up
- Додаємо helm репозиторій
helm repo add k8up-io https://k8up-io.github.io/k8up
- Встановлюємо k8up реліз і k8up-crd
helm install k8up k8up-io/k8up -n k8up kubectl apply -f https://github.com/k8up-io/k8up/releases/download/k8up-4.8.4/k8up-crd.yaml --server-side
Так як bitnami репозиторій вже не публічний, то в values helm чарту k8up треба змінити репозиторій
helm show values k8up-io/k8up > values.yaml
- values.yaml
cleanup: repository: portainer/kubectl-shell
Далі встановлюємо cert-manager та ingress controller:
- Встановлюємо cert-manager
helm repo add jetstack https://charts.jetstack.io --force-update helm install cert-manager oci://quay.io/jetstack/charts/cert-manager --version v1.18.2 --namespace cert-manager --create-namespace --set crds.enabled=true
- Встановлюємо ingress contoller traefik
kubectl create namespace traefik-namespace helm repo add traefik https://helm.traefik.io/traefik helm repo update helm install --namespace=traefik-namespace traefik traefik/traefik
- Редактуємо traefik service та додаємо annotations
annotations: "lbipam.cilium.io/sharing-key": "password"
Пароль беремо в параметрах послуги
Налаштовуємо генерацію сертифікатів LetsEncrypt. Email має бути реальним:
- Створюємо тестовий issuer.
- letsencrypt-staging.yaml
--- apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-staging spec: acme: email: hello@example.com server: https://acme-staging-v02.api.letsencrypt.org/directory privateKeySecretRef: name: letsencrypt-prod-key solvers: - http01: ingress: class: traefik serviceType: ClusterIP
- Створюємо production issuer
- letsencrypt-prod.yaml
--- apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod spec: acme: email: hello@example.com server: https://acme-v02.api.letsencrypt.org/directory privateKeySecretRef: name: letsencrypt-prod-key solvers: - http01: ingress: class: traefik serviceType: ClusterIP
Встановлення mysql:
- Встановлюємо percona mysql operator. Документацію можна знайти тут https://docs.percona.com/percona-operator-for-mysql/pxc/index.html
helm repo add percona https://percona.github.io/percona-helm-charts/ helm repo update kubectl create namespace mysql-operator helm install mysql-operator percona/pxc-operator --namespace mysql-operator
Створюємо базу даних:
- Отримуємо конфігурацію helm чарту
helm show values percona/pxc-db > values.yaml
- Встановлюємо ресурси limit і reqest та storageclass та s3 endpoint і backup
- values.yaml
# приклад конфігурації ... pxc: size: 3 resources: requests: memory: 1G cpu: 600m limits: memory: 1G # cpu: 600m persistence: enabled: true storageClass: "sc-name" accessMode: ReadWriteOnce size: 8Gi ... haproxy: enabled: true size: 3 resources: requests: memory: 200Mi cpu: 200m limits: memory: 400Mi # cpu: 400m ... logcollector: enabled: true resources: requests: memory: 100M cpu: 200m limits: memory: 100M # A custom Kubernetes Security Context for a Container to be used instead of the default one containerSecurityContext: privileged: false ... backup: enabled: true storages: fs-pvc: type: filesystem volume: persistentVolumeClaim: storageClassName: sc-name accessModes: ["ReadWriteOnce"] resources: requests: storage: 10Gi minio: type: s3 verifyTLS: false # якщо використовується s3 сервер з самопідпісаним сертифікатом resources: requests: memory: 1Gi cpu: 600m s3: bucket: S3-BACKUP-BUCKET-NAME-HERE # Use credentialsSecret OR credentialsAccessKey/credentialsSecretKey # credentialsSecret: my-cluster-name-backup-s3 credentialsAccessKey: <s3-login-key> credentialsSecretKey: <s3-secret-key> # region: us-west-2 endpointUrl: https://<s3-url> schedule: - name: "daily-backup" schedule: "0 0 * * *" retention: type: "count" count: 3 deleteFromStorage: true storageName: fs-pvc - name: "s3-backup" schedule: "0 1 * * *" retention: type: "count" count: 3 deleteFromStorage: true storageName: minio
Percona operator дозволяє робити бекапи бази даних на persistent volume або на s3. Можна використовувати обидва варіанти одночасно.
- Встановлюємо базу даних
helm install wordpress-db percona/pxc-db --namespace mysql-operator -f values.yaml
Беремо пароль root бази даних в secret wordpress-db-pxc-db-secrets, який знаходиться в namespace mysql-operator
Встановлення wordpress:
- Створюємо deployment маніфест
- wordpress.yaml
--- apiVersion: v1 kind: Secret metadata: name: mysql-secret type: Opaque data: # пароль root сервера баз даних, який ми беремо з secret wordpress-db-pxc-db-secrets MYSQL_ROOT_PASSWORD: SDc4XjFRMW1zUWgraD1XWiVZXw== --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: wordpress-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi storageClassName: "sc-name" --- apiVersion: apps/v1 kind: Deployment metadata: name: wordpress spec: replicas: 1 selector: matchLabels: app: wordpress template: metadata: labels: app: wordpress spec: containers: - name: wordpress image: wordpress:5.8.3-php7.4-apache resources: limits: memory: 1Gi requests: cpu: 500m memory: 1Gi ports: - containerPort: 80 name: wordpress volumeMounts: - name: wordpress-data mountPath: /var/www/html env: - name: WORDPRESS_DB_HOST # FQDN сервісу складається з service-name.service-namespace.svc.cluster.local value: wordpress-mysql-haproxy.mysql-operator.svc.cluster.local - name: WORDPRESS_DB_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: MYSQL_ROOT_PASSWORD - name: WORDPRESS_DB_USER value: root - name: WORDPRESS_DB_NAME value: mysql volumes: - name: wordpress-data persistentVolumeClaim: claimName: wordpress-pvc --- kind: Service apiVersion: v1 metadata: name: wordpress-service spec: selector: app: wordpress ports: - name: http protocol: TCP port: 80 targetPort: 80 --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: wordpress-ingress namespace: wordpress annotations: traefik.ingress.kubernetes.io/router.entrypoints: websecure traefik.ingress.kubernetes.io/router.tls: "true" # тут вказуємо issuer, який ми створили раніше cert-manager.io/cluster-issuer: letsencrypt-prod spec: rules: # Доменне ім'я прив'язуємо до IP, яке отримав ingress controller - host: example.com.ua http: paths: - path: / pathType: Prefix backend: service: name: wordpress-service port: number: 80 tls: - secretName: web-app-cert hosts: - example.com.ua
- Створюємо namespace для wordpress і деплоїмо wordpress в цей namespace
kubectl create ns wordpress kubectl apply -f wordpress.yaml -n wordpress
Бекап волюмів за допомогою k8up:
- Підготовлюємо параметри доступу до s3 сховища
echo -n '<s3-secret>' > S3_ACCOUNT_KEY # це пароль до S3 echo -n '<s3-key>' > S3_ACCOUNT_NAME # це логін до S3 echo -n '<password>' > RESTIC_PASSWORD # це довільний пароль до репозиторію, який свторить restic під час бекапу kubectl create secret generic -n wordpress secret-backup-host --from-file=./RESTIC_PASSWORD --from-file=./S3_ACCOUNT_NAME --from-file=./S3_ACCOUNT_KEY
- Якщо S3 має самопідписаний сертифікат, то додаємо CA, яким був підписаний сертифікат S3 сервера, до поду який буде створюватись під час бекапу
kubectl create secret generic -n wordpress ca-tls --from-file=./CA.crt
- Створюємо маніфест бекапу
- wordpress-backup.yaml
--- apiVersion: k8up.io/v1 kind: Backup metadata: name: wordpress-backup spec: failedJobsHistoryLimit: 2 successfulJobsHistoryLimit: 2 backend: repoPasswordSecretRef: name: secret-test-backup key: RESTIC_PASSWORD s3: endpoint: <s3-url> bucket: test-1 accessKeyIDSecretRef: name: secret-test-backup key: S3_ACCOUNT_NAME secretAccessKeySecretRef: name: secret-test-backup key: S3_ACCOUNT_KEY # цю частину треба додавати, якщо використовується самопідписаний сертифікат tlsOptions: caCert: /mnt/ca/CA.crt volumeMounts: - name: ca-tls mountPath: /mnt/ca/ volumes: - name: ca-tls secret: secretName: ca-tls defaultMode: 420
- Деплоїмо його в неймспейс де ми хочемо робити бекап
kubectl apply -f wordpress-backup.yaml -n wordpress
k8up шукає всі persistentVolumeClaim в неймспейсі і бекапить їх. Під час виконання бекапу створюється pod, який виконує бекап.
Відновлення даних з бекапу:
Відновлювати треба в існуючий persistentvolumeclaim
- Дивимось k8up снепшоти
kubectl get snapshots -A kubectl get snapshot <snapshot_name> -n wordpress -o yaml
Отримуємо подібний конфіг
--- apiVersion: k8up.io/v1 kind: Snapshot metadata: creationTimestamp: "2025-09-12T12:32:51Z" generation: 1 name: b8528e47 namespace: wordpress resourceVersion: "526600" uid: 57e84ef5-0566-42ff-9850-ad6537e0ea1f spec: date: "2025-09-12T12:32:40Z" id: b8528e47712b2c24a35a3e7c6edb553804206b0ea31e97a654e7545a8ec71c67 paths: - /data/wordpress-pvc repository: s3:<s3-url>/test-1
- Беремо значення id і створюємо маніфест відновлення з бекапу.
- wordpress-restore.yaml
--- apiVersion: k8up.io/v1 kind: Restore metadata: name: restore-test-backup spec: snapshot: b8528e47712b2c24a35a3e7c6edb553804206b0ea31e97a654e7545a8ec71c67 restoreMethod: folder: claimName: "pvc-name" backend: repoPasswordSecretRef: name: secret-test-backup key: RESTIC_PASSWORD s3: endpoint: <s3-url> bucket: test-1 accessKeyIDSecretRef: name: secret-test-backup key: S3_ACCOUNT_NAME secretAccessKeySecretRef: name: secret-test-backup key: S3_ACCOUNT_KEY # цю частину треба додавати, якщо використовується самопідписаний сертифікат tlsOptions: caCert: /mnt/ca/CA.crt volumeMounts: - name: ca-tls mountPath: /mnt/ca/ volumes: - name: ca-tls secret: secretName: ca-tls defaultMode: 420
- Деплоїмо в неймспейс де знаходиться persistentVolumeClaim на який ми хочемо відновити дані.
kubectl apply -f restore-test.yaml -n wordress
Бекап і відновлення бази даних за допомогою percona operator
Офіційну документацію можна знайти по посиланнями:
https://docs.percona.com/percona-operator-for-mysql/pxc/backups.html
https://docs.percona.com/percona-operator-for-mysql/pxc/backups-restore.html
Відновлення з persistentVolumeClaim:
- Створюємо маніфест
- mysql-restore-pvc.yaml
--- apiVersion: pxc.percona.com/v1 kind: PerconaXtraDBClusterRestore metadata: name: mysql-restore-pvc spec: pxcCluster: wordpress-db backupName: daily-backup storageName: fs-pvc
- Деплоїмо його в неймспейс де встановлений percona operator
kubectl apply -f mysql-restore-pvc.yaml -n percona-operator
Прогрес відновлення можна дивитись в логах percona-operator
Відновлення з s3:
- Створюємо маніфест
- mysql-restore-s3.yaml
--- apiVersion: pxc.percona.com/v1 kind: PerconaXtraDBClusterRestore metadata: name: mysql-restore-s3 spec: pxcCluster: wordpress-db backupName: sat-night-backup storageName: minio
- Деплоїмо його в неймспейс де встановлений percona operator
kubectl apply -f mysql-restore-s3.yaml -n percona-operator
Приватне registry
- Створення secret з параметрами авторизації до приватного registry. Потрібно вказувати namespace в якому поди будуть використовувати це приватне registry:
kubectl create secret docker-registry my-registry-secret \ --docker-server=https://registry.kube.colocall.net \ --docker-username=<user> \ --docker-password=<password> \ --docker-email=<email> -n <namespace>
- Використання secret в конфігурації пода:
apiVersion: v1 kind: Pod metadata: name: private-image-pod spec: containers: - name: app image: registry.kube.colocall.net/user/image-name[:TAG] imagePullSecrets: - name: my-registry-secret
- Pull та Push за допомогою docker
docker tag image-name registry.kube.colocall.net/user/image-name:version docker push registry.kube.colocall.net/user/image-name:version docker pull registry.kube.colocall.net/user/image-name:version
Посилання на документації інструментів, які використані в цьому прикладі: