Pengalaman kami dengan Operator Postgres untuk Kubernetes oleh Zalando
Upaya kami dalam menganalisis operator Kubernetes yang ada untuk PostgreSQL menghasilkan perbandingan ini . Dan sekarang kami ingin berbagi pengalaman praktis dan pelajaran menarik yang kami peroleh saat menggunakan solusi pilihan kami — Operator Postgres oleh Zalando .
Menginstal dan memulai
Untuk menerapkan operator, unduh rilis terkini dari GitHub dan terapkan file YAML dari direktori manifests . Atau, Anda dapat menggunakan OperatorHub .
Setelah instalasi selesai, lanjutkan ke pengaturan penyimpanan log dan cadangan . Hal ini dilakukan melalui postgres-operator
ConfigMap di namespace tempat operator diinstal. Baiklah, mari kita lanjutkan ke penerapan klaster PostgreSQL pertama.
Berikut manifest penyebaran kami:
apiVersion: acid.zalan.do/v1
kind: postgresql
metadata:
name: staging-db
spec:
numberOfInstances: 3
patroni:
synchronous_mode: true
postgresql:
version: "12"
resources:
limits:
cpu: 100m
memory: 1Gi
requests:
cpu: 100m
memory: 1Gi
sidecars:
- env:
- name: DATA_SOURCE_URI
value: 127.0.0.1:5432
- name: DATA_SOURCE_PASS
valueFrom:
secretKeyRef:
key: password
name: postgres.staging-db.credentials
- name: DATA_SOURCE_USER
value: postgres
image: wrouesnel/postgres_exporter
name: prometheus-exporter
resources:
limits:
cpu: 500m
memory: 100Mi
requests:
cpu: 100m
memory: 100Mi
teamId: staging
volume:
size: 2Gi
Manifes ini membuat kluster yang terdiri dari tiga instans dengan kontainer sidecar postgres_exporter terlampir yang digunakan untuk mengekspor metrik server PostgreSQL. Seperti yang dapat Anda lihat, prosesnya sangat mudah, dan Anda dapat menyebarkan kluster sebanyak yang Anda inginkan.
Yang perlu diperhatikan adalah antarmuka grafis “untuk pengalaman pengguna database-sebagai-layanan yang nyaman” yang disebut postgres-operator-ui . Antarmuka ini dibundel dengan operator dan memungkinkan Anda membuat dan menghapus kluster serta mengelola dan memulihkan cadangan operator.
Fitur lain yang mengesankan dari operator ini adalah dukungan untuk Teams API . Teams API secara otomatis membuat peran PostgreSQL menggunakan daftar nama pengguna. Kemudian, ia dapat menampilkan daftar pengguna yang perannya dibuat secara otomatis.
Masalah dan solusi
Namun, kami mencatat beberapa kekurangan yang mendesak pada operator:
- ketidakmampuan untuk menonaktifkan cadangan;
- masalah dengan kluster PostgreSQL sinkron;
- hak istimewa tidak ditetapkan secara default saat membuat database;
- terkadang, dokumentasinya tidak tersedia atau sudah kedaluwarsa.
Untungnya, banyak di antaranya yang dapat dipecahkan. Mari kita mulai dari akhir ( dokumentasinya kurang baik ) dan lanjutkan ke awal daftar.
Suatu hari, Anda mungkin menemukan bahwa tidak ada deskripsi terperinci dalam dokumentasi tentang cara mendaftarkan cadangan dalam konfigurasi dan cara menghubungkan bucket cadangan ke UI Operator. PR ini dapat membantu Anda dalam memecahkan masalah ini:
- Anda harus membuat rahasia;
- dan meneruskannya ke
pod_environment_secret_name
parameter yang ditentukan dalam CRD pengaturan operator atau dalam ConfigMap (tergantung pada cara operator diinstal).
Namun, ternyata hal ini tidak memungkinkan. Itulah sebabnya kami membuat versi operator kami sendiri dengan beberapa tambahan dari pihak ketiga; di bawah ini, Anda akan menemukan informasi lebih lanjut mengenai hal tersebut.
Jika Anda meneruskan parameter cadangan ke operator (yaitu, wal_s3_bucket
dan kunci untuk mengakses AWS S3), operator akan membuat cadangan basis data produksi dan pementasan. Kami sama sekali tidak menyukai perilaku seperti itu.
Namun, kami menemukan celah menarik dalam deskripsi parameter Spilo (Spilo adalah pembungkus Docker dasar untuk PgSQL): ternyata, Anda dapat meneruskan WAL_S3_BUCKET
parameter kosong, sehingga menonaktifkan pencadangan. Untungnya, kami menemukan PR siap pakai yang mengimplementasikan fungsionalitas tersebut, dan kami segera menggabungkannya ke dalam fork kami. Sekarang Anda hanya perlu menambahkan parameter enableWALArchiving: false
ke konfigurasi sumber daya klaster PostgreSQL.
Sebenarnya, ada pilihan lain: kita dapat menjalankan dua operator terpisah, satu untuk lingkungan staging (dengan pencadangan dinonaktifkan) dan satu lagi untuk lingkungan produksi. Namun, cara yang kita pilih membantu kita menangani semuanya hanya dengan satu operator.
Oke, kami telah menemukan cara untuk menentukan parameter S3 dalam konfigurasi basis data, dan cadangan mulai masuk ke penyimpanan. Namun, bagaimana Anda mengonfigurasi UI Operator agar berfungsi dengan cadangan?
Ternyata, Anda perlu menambahkan tiga variabel berikut ke UI Operator:
SPILO_S3_BACKUP_BUCKET
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
Setelah itu, Anda akan dapat mengelola cadangan. Dalam kasus kami, ini menyederhanakan pengoperasian lingkungan pementasan, yang memungkinkan Anda menambahkan snapshot produksi ke dalamnya tanpa skrip tambahan.
Di atas, kami menyebutkan Teams API dan opsi ekstensifnya untuk membuat basis data dan peran menggunakan operator sebagai keuntungan yang jelas. Namun, peran yang dibuat tidak memiliki hak istimewa yang sesuai secara default . Dengan kata lain, pengguna dengan akses "baca" tidak dapat membaca tabel baru.
Mengapa demikian? Masalahnya adalah, meskipun kode tersebut telah menetapkan semua GRANT yang diperlukan, GRANT tersebut tidak selalu diterapkan. Ada 2 metode: syncPreparedDatabases
dan syncDatabases
. Metode ini syncPreparedDatabases
tidak menerapkan hak istimewa secara default (meskipun kunci defaultRoles
dan defaultUsers
ditetapkan di preparedDatabases
bagian manifes). Saat ini, kami sedang mempersiapkan patch untuk menetapkan hak istimewa ini secara otomatis.
Masalah yang disebutkan dengan kluster PgSQL sinkron dilaporkan di sini .
Apa yang kita dapatkan pada akhirnya?
Saat mencoba memecahkan semua masalah ini, Operator Postgres oleh Zalando di-fork di sini , tempat kami menerapkan semua patch yang diperlukan. Dan kami juga telah membangun image Docker demi kenyamanan.
Berikut adalah daftar PR yang digabungkan ke dalam fork kami:
- membangun citra operator yang aman dan ringan melalui Dockerfile ;
- nonaktifkan pengarsipan WAL ;
- memperbarui jenis sumber daya agar berfungsi dengan versi K8s saat ini .
Harap dukung PR ini agar dapat masuk ke hulu pada versi operator berikutnya (1.7).
Migrasi produksi: kisah sukses kami
Sementara itu, kami ingin berbagi pengalaman migrasi kami. Ya, ada cara untuk memigrasikan produksi yang aktif dan berjalan dengan waktu henti minimal menggunakan Operator Zalando Postgres dan templat Patroni.
Dengan citra Spilo Docker, Anda dapat menyebarkan klaster siaga menggunakan penyimpanan S3 dan WAL-E . Dalam kasus ini, log biner PgSQL pertama-tama disimpan ke penyimpanan S3, lalu ditarik oleh replika. Namun, bagaimana jika Anda tidak memiliki WAL-E di infrastruktur lama?
Dalam kasus ini, Anda dapat menggunakan replikasi logis PostgreSQL. Namun, kami tidak akan membahas detail pembuatan publikasi/langganan untuk ini, karena... yah, rencana kami telah gagal.
Masalahnya adalah basis data kami memiliki beberapa tabel yang sangat banyak memuat jutaan baris, dan baris-baris ini terus diperbarui dan dihapus. Langganancopy_data
berbasis sederhana (ketika replika baru menyalin semua data dari master) tidak dapat mengimbangi master. Ia menyalin konten selama seminggu penuh tetapi tidak pernah mengejar master. Pada akhirnya, kami menggunakan metode yang diusulkan oleh rekan-rekan Avito kami: kami mentransfer data menggunakan . Jadi, berikut ini versi algoritme mereka (yang sedikit dimodifikasi).pg_dump
Idenya adalah membuat langganan "kosong" yang ditautkan ke slot replikasi yang ada, lalu memperbaiki nomor LSN. Dalam kasus kami, ada dua replika produksi. Ini penting karena replika dapat membantu Anda membuat dump yang konsisten dan terus mendapatkan data dari master.
Kami akan menggunakan penunjukan host berikut saat menjelaskan proses migrasi:
- master — server sumber;
- replica1 — replika streaming dalam produksi “lama”;
- replica2 — replika logis yang baru.
Rencana migrasi
- Buat langganan ke semua tabel dalam
public
skema databasedbname
di master:psql -h master -d dbname -c "CREATE PUBLICATION dbname FOR ALL TABLES;"
- Buat slot replikasi pada master:
psql -h master -c "select pg_create_logical_replication_slot('repl', 'pgoutput');"
- Hentikan replikasi pada replika lama:
psql -h replica1 -c "select pg_wal_replay_pause();"
Dapatkan LSN di master:
psql -h master -c "select replay_lsn from pg_stat_replication where client_addr = 'replica1';"
- Buang data pada replika lama (Anda dapat menggunakan beberapa utas untuk mempercepat proses):
pg_dump -h replica1 --no-publications --no-subscriptions -O -C -F d -j 8 -f dump/ dbname
- Unggah dump ke server baru:
pg_restore -h replica2 -F d -j 8 -d dbname dump/
- Setelah pengunggahan selesai, lanjutkan replikasi pada replika streaming:
psql -h replica1 -c "select pg_wal_replay_resume();"
- Buat langganan pada replika logis baru:
psql -h replica2 -c "create subscription oldprod connection 'host=replica1 port=5432 user=postgres password=secret dbname=dbname' publication dbname with (enabled = false, create_slot = false, copy_data = false, slot_name='repl');"
- Dapatkan tambahan langganan:
psql -h replica2 -d dbname -c "select oid, * from pg_subscription;"
- Misalnya, oid kita sama dengan 1000. Terapkan LSN ke langganan:
psql -h replica2 -d dbname -c "select pg_replication_origin_advance('pg_1000', 'AA/AAAAAAAA');"
- Aktifkan replikasi:
psql -h replica2 -d dbname -c "alter subscription oldprod enable;"
- Periksa status langganan; replikasi harus berjalan:
psql -h replica2 -d dbname -c "select * from pg_replication_origin_status;" psql -h master -d dbname -c "select slot_name, restart_lsn, confirmed_flush_lsn from pg_replication_slots;"
- Jika replikasi berjalan normal dan basis data tersinkronisasi, Anda dapat beralih ke host baru.
- Setelah replikasi dinonaktifkan, Anda perlu memperbaiki urutannya. (Deskripsi terperinci tentang proses ini tersedia di wiki.postgresql.org .)
Berkat rencana ini, migrasi berlangsung dengan penundaan minimal.
Beberapa catatan lainnya
Dengan menggunakan Operator Postgres oleh Zalando setiap hari, kami telah menghadapi berbagai tantangan. Berikut ini beberapa kasus yang kami tangani.
1. Repositori pribadi
Suatu kali kami perlu menjalankan kontainer SFTP di kluster PostgreSQL kami melalui operator untuk mengambil data basis data dalam format CSV. Server SFTP dengan semua parameter yang diperlukan disimpan dalam registri pribadi.
Kami terkejut saat mengetahui bahwa operator tidak dapat menangani rahasia registri. Untungnya, masalah ini cukup umum, dan kami segera menyelesaikannya menggunakan metode yang dirancang oleh rekan-rekan dalam masalah ini . Ternyata kami hanya perlu menambahkan nama dan rahasia registri ke definisi ServiceAccount:
pod_service_account_definition: '{ "apiVersion": "v1", "kind": "ServiceAccount", "metadata": { "name": "zalando-postgres-operator" }, "imagePullSecrets": [ { "name": "my-fine-secret" } ] }'
2. Penyimpanan tambahan dan kontainer init
Dalam kasus SFTP, kami juga perlu menetapkan izin direktori yang benar agar chroot dapat berfungsi. Anda mungkin menyadari fakta bahwa server OpenSSH memerlukan hak akses direktori khusus. Misalnya, agar pengguna dapat menggunakan direktori home-nya ( /home/user
), induk ( /home
direktori ) harus dimiliki oleh root dan memerlukan 755 izin. Kami memutuskan untuk menggunakan kontainer init yang akan memperbaiki izin tersebut.
Namun kemudian kami menemukan bahwa operator tidak dapat memasang volume tambahan dalam kontainer init! Untungnya, kami menemukan PR terkait dan menambahkannya ke build kami .
3. Membuat ulang kontainer
Berikut ini adalah masalah menarik terakhir (tetapi tidak kalah pentingnya). Dalam rilis operator sebelumnya , sidecar global baru telah ditambahkan. Sekarang Anda dapat mendefinisikannya dalam CRD operator. Pengembang kami memperhatikan restart berkala pada basis data. Log operator berisi informasi berikut:
time="2020-10-28T20:58:25Z" level=debug msg="spec diff between old and new statefulsets: \n
Template.Spec.Volumes[2].VolumeSource.ConfigMap.DefaultMode: &int32(420) != nil\n
Template.Spec.Volumes[3].VolumeSource.ConfigMap.DefaultMode: &int32(420) != nil\n
Template.Spec.Containers[0].TerminationMessagePath: \"/dev/termination-log\" != \"\"\nTemplate.Spec.Containers[0].TerminationMessagePolicy: \"File\" != \"\"\nTemplate.Spec.Containers[1].Ports[0].Protocol: \"TCP\" != \"\"\n
Template.Spec.Containers[1].TerminationMessagePath: \"/dev/termination-log\" != \"\"\nTemplate.Spec.Containers[1].TerminationMessagePolicy: \"File\" != \"\"\nTemplate.Spec.RestartPolicy: \"Always\" != \"\"\n
Template.Spec.DNSPolicy: \"ClusterFirst\" != \"\"\n
Template.Spec.DeprecatedServiceAccount: \"postgres-pod\" != \"\"\n
Template.Spec.SchedulerName: \"default-scheduler\" != \"\"\n
VolumeClaimTemplates[0].Status.Phase: \"Pending\" != \"\"\nRevisionHistoryLimit: &int32(10) != nil\n
" cluster-name=test/test-psql pkg=cluster worker=0
Seperti yang Anda ketahui, ada beberapa perintah yang tidak didefinisikan tetapi tetap ditambahkan selama pembuatan pod dan container. Perintah-perintah ini meliputi:
- Kebijakan DNS;
- NamaPenjadwal;
- KebijakanMulai Ulang;
- KebijakanPesanPenghentian;
- …
Tampaknya masuk akal untuk berasumsi bahwa operator mempertimbangkan hal ini. Namun ternyata operator memperlakukan ports
bagian tersebut dengan tidak semestinya:
ports:
- name: sftp
containerPort: 22
Protokol TCP ditambahkan secara otomatis saat membuat pod. Namun, operator mengabaikannya. Untuk mengatasi masalah di atas, Anda perlu menghapus port atau menambahkan protokol.
Kesimpulan
Operator Kubernetes mengotomatiskan berbagai tugas dengan menggunakan sumber daya khusus untuk mengelola aplikasi dan komponennya. Namun, otomatisasi yang mengesankan ini menghadirkan beberapa nuansa yang tidak terduga, jadi pilihlah operator Anda dengan bijak.
Pengalaman kami menunjukkan bahwa Anda tidak boleh berharap dapat menyelesaikan semua masalah dengan cepat dan ajaib. Dengan menggunakan Postgres Operator by Zalando, kami telah melalui beberapa kesulitan, tetapi kami tetap puas dengan hasilnya dan berencana untuk memperluas pengalaman kami ke instalasi PostgreSQL lainnya.
Tidak ada komentar:
Posting Komentar