Jaga pengguna basis data tetap sinkron¶
Pengguna basis data membuat pengguna tenax satu kali. Itu sudah cukup untuk sebagian besar
penyiapan. Halaman ini untuk penyiapan GitOps tempat pengguna harus terus sesuai dengan Secret-nya tanpa ada orang
yang menjalankan apa pun:
- kata sandi di Secret dirotasi;
- basis data dibangun ulang atau dipulihkan dari dump lama, dan penggunanya hilang;
- seseorang mengubah pengguna secara manual (mencabut grant, mengganti kata sandi);
- basis data dibuat setelah manifest yang mendeskripsikan penggunanya (klaster baru).
Job sekali jalan tidak menangani satu pun dari kasus ini: ia berjalan sekali, dan Kubernetes tidak akan menjalankan ulang Job yang sudah selesai ketika Secret berubah. CronJob yang menerapkan ulang SQL idempoten yang sama bisa menanganinya: dalam satu periode, pengguna kembali sesuai dengan Secret.
Cara kerjanya¶
Satu CronJob per basis data, di namespace basis data tersebut. Setiap kali berjalan, ia:
- menunggu sampai basis data merespons (dibatasi oleh deadline Job);
- login sebagai administrator, memakai Secret yang digunakan basis data itu sendiri;
- membuat pengguna
tenaxjika belum ada, lalu mengatur kata sandi dan grant-nya dari Secret Tenax.
Setiap pernyataan bersifat idempoten, jadi proses yang mendapati semuanya sudah sesuai tidak mengubah apa pun. Kata sandi sampai ke container sebagai environment variable dari Secret; kata sandi tidak pernah muncul di baris perintah atau di log.
PostgreSQL¶
Ganti empat nilai yang ditandai # ←: namespace, Service basis data, basis data, serta Secret dan key yang menyimpan
kata sandi administrator.
apiVersion: batch/v1
kind: CronJob
metadata:
name: tenax-user-postgres
namespace: team-a # ←
spec:
schedule: "*/30 * * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 1
failedJobsHistoryLimit: 3
jobTemplate:
spec:
backoffLimit: 2
activeDeadlineSeconds: 300
template:
spec:
restartPolicy: OnFailure
automountServiceAccountToken: false
securityContext: { runAsNonRoot: true, runAsUser: 999, runAsGroup: 999 }
containers:
- name: psql
image: docker.io/library/postgres:16
resources: { requests: { cpu: 10m, memory: 32Mi }, limits: { memory: 128Mi } }
securityContext: { allowPrivilegeEscalation: false, capabilities: { drop: [ALL] } }
env:
- { name: PGHOST, value: postgres } # ← the database's Service
- { name: PGDATABASE, value: app } # ← any database on the server
- { name: PGUSER, value: postgres }
- { name: PGCONNECT_TIMEOUT, value: "10" }
- name: PGPASSWORD
valueFrom: { secretKeyRef: { name: postgres-admin, key: password } } # ←
- name: TENAX_PASSWORD
valueFrom: { secretKeyRef: { name: tenax-postgres, key: password } }
command: [sh, -ec]
args:
- |
until pg_isready -q; do echo "waiting for $PGHOST"; sleep 5; done
psql -v ON_ERROR_STOP=1 -X <<'SQL'
\getenv tenax_password TENAX_PASSWORD
SELECT 'CREATE ROLE tenax LOGIN REPLICATION' WHERE NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'tenax') \gexec
ALTER ROLE tenax WITH LOGIN REPLICATION NOSUPERUSER NOCREATEDB NOCREATEROLE PASSWORD :'tenax_password';
GRANT pg_read_all_data, pg_monitor TO tenax;
ALTER ROLE tenax SET idle_in_transaction_session_timeout = '10min';
SQL
echo "tenax user in sync on $PGHOST"
\getenv memerlukan psql 15 atau yang lebih baru di dalam image; servernya bisa versi apa pun yang didukung. Atur
max_slot_wal_keep_size lewat konfigurasi server (misalnya -c max_slot_wal_keep_size=2GB), bukan di sini: itu
adalah pengaturan server, bukan bagian dari pengguna.
MySQL¶
apiVersion: batch/v1
kind: CronJob
metadata:
name: tenax-user-mysql
namespace: team-a # ←
spec:
schedule: "*/30 * * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 1
failedJobsHistoryLimit: 3
jobTemplate:
spec:
backoffLimit: 2
activeDeadlineSeconds: 300
template:
spec:
restartPolicy: OnFailure
automountServiceAccountToken: false
securityContext: { runAsNonRoot: true, runAsUser: 999, runAsGroup: 999 }
containers:
- name: mysql
image: docker.io/library/mysql:8.4
resources: { requests: { cpu: 10m, memory: 64Mi }, limits: { memory: 256Mi } }
securityContext: { allowPrivilegeEscalation: false, capabilities: { drop: [ALL] } }
env:
- { name: MYSQL_HOST, value: mysql } # ← the database's Service
- name: ROOT_PASSWORD
valueFrom: { secretKeyRef: { name: mysql-admin, key: root-password } } # ←
- name: TENAX_PASSWORD
valueFrom: { secretKeyRef: { name: tenax-mysql, key: password } }
command: [bash, -ec]
args:
- |
umask 077
printf '[client]\nuser=root\npassword=%s\nhost=%s\nconnect-timeout=10\n' "$ROOT_PASSWORD" "$MYSQL_HOST" > /tmp/root.cnf
until mysqladmin --defaults-extra-file=/tmp/root.cnf ping --silent; do echo "waiting for $MYSQL_HOST"; sleep 5; done
mysql --defaults-extra-file=/tmp/root.cnf <<SQL
CREATE USER IF NOT EXISTS 'tenax'@'%' IDENTIFIED BY '${TENAX_PASSWORD}';
ALTER USER 'tenax'@'%' IDENTIFIED BY '${TENAX_PASSWORD}';
GRANT SELECT, SHOW VIEW, TRIGGER, EVENT, LOCK TABLES, PROCESS, RELOAD, SHOW_ROUTINE,
REPLICATION CLIENT, REPLICATION SLAVE ON *.* TO 'tenax'@'%';
SQL
rm -f /tmp/root.cnf
echo "tenax user in sync on $MYSQL_HOST"
Kata sandi dimasukkan ke SQL tanpa escaping, hanya diapit tanda kutip string literal, jadi buatlah dalam format hex
(openssl rand -hex 24).
Jalankan sekarang¶
kubectl -n team-a create job --from=cronjob/tenax-user-postgres tenax-user-now
kubectl -n team-a logs -f job/tenax-user-now
Setiap 30 menit sudah lebih dari cukup: Tenax sendiri mencoba ulang login yang ditolak dan melaporkannya pada target,
jadi rotasi akan terambil paling lambat satu periode kemudian. Aturan pg_hba.conf dan pengaturan binlog tetap
menjadi konfigurasi server (Pengguna basis data, langkah 3); CronJob ini tidak menyentuhnya.