Mencoba alat baru untuk membangun dan mengotomatiskan penyebaran di Kubernetes


Hai Baru-baru ini, banyak alat otomatisasi keren telah dirilis baik untuk membangun gambar Docker dan untuk digunakan ke Kubernetes. Dalam hal ini, saya memutuskan untuk bermain dengan gitlab, bagaimana mempelajari kemampuannya dan, tentu saja, mengkonfigurasi pipeline.


Inspirasi untuk pekerjaan ini adalah situs kubernetes.io , yang secara otomatis dihasilkan dari kode sumber , dan untuk setiap kumpulan yang dikirim, robot secara otomatis membuat versi pratinjau situs dengan perubahan Anda dan menyediakan tautan untuk dilihat.


Saya mencoba untuk membangun proses serupa dari awal, tetapi seluruhnya berdasarkan pada Gitlab CI dan alat gratis yang saya gunakan untuk menggunakan aplikasi di Kubernetes. Hari ini saya akhirnya akan memberi tahu Anda lebih banyak tentang mereka.


Artikel tersebut akan mempertimbangkan alat-alat seperti:
Hugo , qbec , kaniko , git-crypt dan GitLab CI dengan penciptaan lingkungan yang dinamis.




Isi


  1. Memperkenalkan Hugo
  2. Mempersiapkan Dockerfile
  3. Kenalan dengan kaniko
  4. Memperkenalkan qbec
  5. Mencoba Gitlab-runner dengan Kubernetes-executor
  6. Penempatan grafik Helm dengan qbec
  7. Memperkenalkan git-crypt
  8. Buat gambar toolbox
  9. Pipa pertama kami dan kumpulan gambar dengan tag
  10. Otomasi Penerapan
  11. Artefak dan push build in master
  12. Lingkungan yang dinamis
  13. Tinjau Aplikasi



1. Memperkenalkan Hugo


Sebagai contoh proyek kami, kami akan mencoba membuat situs web untuk penerbitan dokumentasi yang dibangun di atas Hugo. Hugo adalah generator konten statis.


Bagi mereka yang tidak terbiasa dengan generator statis, saya akan memberi tahu Anda lebih banyak tentang mereka. Tidak seperti mesin situs database biasa dan beberapa mesin php yang, ketika diminta oleh pengguna, menghasilkan halaman dengan cepat, generator statis diatur sedikit berbeda. Mereka memungkinkan Anda untuk mengambil sumber, sebagai aturan itu adalah satu set file di markup markdown dan template tema, kemudian kompilasi mereka ke situs yang sudah selesai.


Artinya, pada output Anda akan mendapatkan struktur direktori dan satu set file html yang dihasilkan yang dapat dengan mudah diunggah ke hosting murah dan mendapatkan situs yang berfungsi.


Hugo dapat diinstal secara lokal dan mencobanya:


Kami menginisialisasi situs baru:


hugo new site docs.example.org 

Dan pada saat yang sama repositori git:


 cd docs.example.org git init 

Sejauh ini, situs kami masih asli dan untuk sesuatu yang muncul terlebih dahulu kita perlu menghubungkan tema, tema - itu hanya seperangkat template dan aturan yang telah ditetapkan oleh mana situs kami dihasilkan.


Sebagai topik, kami akan menggunakan Learn , yang, menurut pendapat saya, paling cocok untuk situs dengan dokumentasi.


Saya ingin memberikan perhatian khusus pada kenyataan bahwa kita tidak perlu menyimpan file tema dalam repositori proyek kita, sebagai gantinya kita cukup menghubungkannya menggunakan git submodule :


 git submodule add https://github.com/matcornic/hugo-theme-learn themes/learn 

Dengan demikian, dalam repositori kami hanya akan ada file yang terkait langsung dengan proyek kami, dan topik yang terhubung akan tetap dalam bentuk tautan ke repositori tertentu dan komit di dalamnya, yaitu, selalu dapat ditarik dari sumber asli dan tidak takut akan perubahan yang tidak kompatibel.


Perbaiki config.toml config:


 baseURL = "http://docs.example.org/" languageCode = "en-us" title = "My Docs Site" theme = "learn" 

Sudah pada tahap ini, Anda dapat menjalankan:


 hugo server 

Dan di http: // localhost: 1313 / periksa situs kami yang baru dibuat, semua perubahan yang dilakukan pada direktori secara otomatis diperbarui dan halaman terbuka di browser sangat nyaman!


Mari kita coba membuat halaman sampul dalam konten / _index.md :


 # My docs site ## Welcome to the docs! You will be very smart :-) 

Cuplikan layar halaman yang baru dibuat


Untuk menghasilkan situs, jalankan:


 hugo 

Isi direktori publik / akan menjadi situs Anda.
Ya, omong-omong, mari segera tambahkan ke .gitignore :


 echo /public > .gitignore 

Jangan lupa untuk melakukan perubahan kami:


 git add . git commit -m "New site created" 



2. Mempersiapkan Dockerfile


Inilah saatnya menentukan struktur repositori kami. Biasanya saya menggunakan sesuatu seperti:


 . ├── deploy │ ├── app1 │ └── app2 └── dockerfiles ├── image1 └── image2 

  • dockerfiles / - berisi direktori dengan Dockerfiles dan semua yang Anda butuhkan untuk membangun gambar buruh pelabuhan kami.
  • deploy / - berisi direktori untuk menyebarkan aplikasi kami ke Kubernetes

Jadi, kita akan membuat Dockerfile pertama kita di sepanjang path dockerfiles / website / Dockerfile


 FROM alpine:3.11 as builder ARG HUGO_VERSION=0.62.0 RUN wget -O- https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_linux-64bit.tar.gz | tar -xz -C /usr/local/bin ADD . /src RUN hugo -s /src FROM alpine:3.11 RUN apk add --no-cache darkhttpd COPY --from=builder /src/public /var/www ENTRYPOINT [ "/usr/bin/darkhttpd" ] CMD [ "/var/www" ] 

Seperti yang Anda lihat, Dockerfile berisi dua FROMs, fitur ini disebut multi-stage build dan memungkinkan Anda untuk mengecualikan semua yang tidak perlu dari gambar buruh pelabuhan akhir.
Dengan demikian, gambar akhir hanya akan berisi darkhttpd (server HTTP ringan) dan publik / - konten situs kami yang dihasilkan secara statis.


Jangan lupa untuk melakukan perubahan kami:


 git add dockerfiles/website git commit -m "Add Dockerfile for website" 



3. Berkenalan dengan kaniko


Sebagai kolektor gambar buruh pelabuhan, saya memutuskan untuk menggunakan kaniko , karena tidak memerlukan daemon buruh pelabuhan untuk bekerja, dan perakitan itu sendiri dapat dilakukan pada mesin apa pun dan menyimpan cache secara langsung dalam registri, sehingga menghilangkan kebutuhan untuk penyimpanan persisten penuh. .


Untuk membangun gambar, mulai saja wadah dengan pelaksana kaniko dan sampaikan konteks pembuatan saat ini, Anda dapat melakukan ini secara lokal, melalui buruh pelabuhan:


 docker run -ti --rm \ -v $PWD:/workspace \ -v ~/.docker/config.json:/kaniko/.docker/config.json:ro \ gcr.io/kaniko-project/executor:v0.15.0 \ --cache \ --dockerfile=dockerfiles/website/Dockerfile \ --destination=registry.gitlab.com/kvaps/docs.example.org/website:v0.0.1 

Di mana registry.gitlab.com/kvaps/docs.example.org/website adalah nama dari gambar buruh pelabuhan Anda, setelah perakitan akan secara otomatis dimasukkan ke dalam register buruh pelabuhan.


Parameter --cache memungkinkan Anda untuk me -cache lapisan dalam register docker, untuk contoh yang diberikan mereka akan disimpan di registry.gitlab.com/kvaps/docs.example.org/website/cache , tetapi Anda dapat menentukan lintasan lain menggunakan parameter --cache- repo .


Screenshot docker-registry




4. Berkenalan dengan qbec


Qbec adalah alat penyebaran yang memungkinkan Anda untuk mendeskripsikan manifes aplikasi Anda dan menyebarkannya ke Kubernetes. Menggunakan Jsonnet sebagai sintaks utama memungkinkan Anda untuk sangat menyederhanakan deskripsi perbedaan untuk beberapa lingkungan, dan juga hampir sepenuhnya menghilangkan pengulangan kode.


Ini bisa benar terutama dalam kasus di mana Anda perlu menyebarkan aplikasi ke beberapa cluster dengan parameter yang berbeda dan Anda ingin menggambarkan secara deklaratif di Git.


Qbec juga memungkinkan Anda untuk membuat grafik Helm dengan memberikan parameter yang diperlukan dan kemudian mengoperasikannya serta manifesto normal, termasuk berbagai mutasi yang dapat ditumpangkan pada mereka, dan ini, pada gilirannya, menghilangkan kebutuhan untuk menggunakan ChartMuseum. Artinya, Anda dapat menyimpan dan membuat grafik langsung dari git, di mana mereka memiliki tempat itu.


Seperti yang saya katakan sebelumnya, kami akan menyimpan semua penyebaran di direktori deploy / :


 mkdir deploy cd deploy 

Mari inisialisasi aplikasi pertama kita:


 qbec init website cd website 

Sekarang struktur aplikasi kita terlihat seperti ini:


 . ├── components ├── environments │  ├── base.libsonnet │  └── default.libsonnet ├── params.libsonnet └── qbec.yaml 

lihat file qbec.yaml :


 apiVersion: qbec.io/v1alpha1 kind: App metadata: name: website spec: environments: default: defaultNamespace: docs server: https://kubernetes.example.org:8443 vars: {} 

Di sini kami terutama tertarik pada spec.environmentments , qbec sudah membuat lingkungan default untuk kami dan mengambil alamat server, serta namespace dari kubeconfig kami saat ini.
Sekarang, ketika menggunakan ke lingkungan default , qbec akan selalu menyebarkan hanya ke cluster Kubernetes yang ditentukan dan ke namespace yang ditentukan, yaitu, Anda tidak lagi harus beralih antara konteks dan ruang nama untuk melakukan penyebaran.
Jika perlu, Anda selalu dapat memperbarui pengaturan dalam file ini.


Semua lingkungan Anda dijelaskan dalam qbec.yaml , dan dalam file params.libsonnet , di mana ia mengatakan di mana Anda perlu mengambil parameter untuk mereka.


Selanjutnya kita melihat dua direktori:


  • komponen / - semua manifes untuk aplikasi kita akan disimpan di sini, mereka dapat dijelaskan baik di jsonnet dan file yaml biasa
  • lingkungan / - di sini kita akan menjelaskan semua variabel (parameter) untuk lingkungan kita.

Secara default, kami memiliki dua file:


  • environment / base.libsonnet - ini akan berisi parameter umum untuk semua lingkungan
  • environment / default.libsonnet - berisi parameter yang diganti untuk lingkungan default

Mari kita buka environment / base.libsonnet dan tambahkan parameter untuk komponen pertama kita di sana:


 { components: { website: { name: 'example-docs', image: 'registry.gitlab.com/kvaps/docs.example.org/website:v0.0.1', replicas: 1, containerPort: 80, servicePort: 80, nodeSelector: {}, tolerations: [], ingressClass: 'nginx', domain: 'docs.example.org', }, }, } 

Kami juga akan membuat komponen komponen / website.jsonnet pertama kami:


 local env = { name: std.extVar('qbec.io/env'), namespace: std.extVar('qbec.io/defaultNs'), }; local p = import '../params.libsonnet'; local params = p.components.website; [ { apiVersion: 'apps/v1', kind: 'Deployment', metadata: { labels: { app: params.name }, name: params.name, }, spec: { replicas: params.replicas, selector: { matchLabels: { app: params.name, }, }, template: { metadata: { labels: { app: params.name }, }, spec: { containers: [ { name: 'darkhttpd', image: params.image, ports: [ { containerPort: params.containerPort, }, ], }, ], nodeSelector: params.nodeSelector, tolerations: params.tolerations, imagePullSecrets: [{ name: 'regsecret' }], }, }, }, }, { apiVersion: 'v1', kind: 'Service', metadata: { labels: { app: params.name }, name: params.name, }, spec: { selector: { app: params.name, }, ports: [ { port: params.servicePort, targetPort: params.containerPort, }, ], }, }, { apiVersion: 'extensions/v1beta1', kind: 'Ingress', metadata: { annotations: { 'kubernetes.io/ingress.class': params.ingressClass, }, labels: { app: params.name }, name: params.name, }, spec: { rules: [ { host: params.domain, http: { paths: [ { backend: { serviceName: params.name, servicePort: params.servicePort, }, }, ], }, }, ], }, }, ] 

Dalam file ini kami segera menggambarkan tiga entitas Kubernetes, yaitu: Deployment , Service , dan Ingress . Jika diinginkan, kita bisa membawanya ke komponen yang berbeda, tetapi pada tahap ini, satu sudah cukup bagi kita.


Sintaks jsonnet sangat mirip dengan json biasa, pada prinsipnya jsonnet reguler sudah jsonnet yang valid, jadi pada awalnya mungkin lebih mudah untuk menggunakan layanan online seperti yaml2json untuk mengonversi yaml Anda menjadi json, atau jika komponen Anda tidak mengandung variabel apa pun, maka mereka dapat digambarkan dalam bentuk yaml biasa.


Ketika bekerja dengan jsonnet, saya sangat menyarankan untuk menginstal plugin untuk editor Anda

Misalnya, untuk vim ada plugin vim-jsonnet yang menyalakan penyorotan sintaks dan secara otomatis melakukan jsonnet fmt setiap kali disimpan (memerlukan jsonnet diinstal).

Semuanya siap, sekarang kita bisa memulai penyebaran:


Untuk melihat apa yang terjadi, kami akan melakukan:


 qbec show default 

Pada output, Anda akan melihat manifes yaml yang diberikan yang akan diterapkan ke cluster default.


Oke, sekarang terapkan:


 qbec apply default 

Di pintu keluar, Anda akan selalu melihat apa yang akan dilakukan di kluster Anda, qbec akan meminta Anda untuk menerima perubahan, dengan mengetik y Anda dapat mengonfirmasi niat Anda.


Selesai, sekarang aplikasi kita merapat!


Jika Anda melakukan perubahan, Anda selalu dapat melakukan:


 qbec diff default 

untuk melihat bagaimana perubahan ini akan mempengaruhi penyebaran saat ini


Jangan lupa untuk melakukan perubahan kami:


 cd ../.. git add deploy/website git commit -m "Add deploy for website" 



5. Mencoba Gitlab-runner dengan Kubernetes-executor


Sampai baru-baru ini, saya hanya menggunakan gitlab-runner biasa pada mesin yang sudah disiapkan (wadah LXC) dengan shell atau docker-executor. Awalnya, kami memiliki beberapa pelari yang didefinisikan secara global di hitlab kami. Mereka mengumpulkan gambar buruh pelabuhan untuk semua proyek.


Tetapi seperti yang telah ditunjukkan oleh praktik, opsi ini bukanlah yang paling ideal, baik dalam hal kepraktisan maupun dalam hal keamanan. Jauh lebih baik dan ideologis lebih tepat untuk memiliki pelari yang terpisah dikerahkan untuk setiap proyek, dan bahkan untuk setiap lingkungan.


Untungnya, ini bukan masalah sama sekali, karena sekarang kami akan menggunakan gitlab-runner secara langsung sebagai bagian dari proyek kami langsung ke Kubernetes.


Gitlab menyediakan bagan helm yang siap pakai untuk menempatkan gitlab-pelari di Kubernetes. Dengan demikian, semua yang perlu Anda lakukan adalah mencari token pendaftaran untuk proyek kami di Pengaturan -> CI / CD -> Pelari dan berikan helm:


 helm repo add gitlab https://charts.gitlab.io helm install gitlab-runner \ --set gitlabUrl=https://gitlab.com \ --set runnerRegistrationToken=yga8y-jdCusVDn_t4Wxc \ --set rbac.create=true \ gitlab/gitlab-runner 

Dimana:


  • https://gitlab.com adalah alamat server Gitlab Anda.
  • yga8y-jdCusVDn_t4Wxc - token pendaftaran untuk proyek Anda.
  • rbac.create = true - Memberi pelari jumlah hak istimewa yang diperlukan untuk dapat membuat pod untuk melakukan tugas kami menggunakan kubernetes-executor.

Jika semuanya dilakukan dengan benar, Anda akan melihat pelari terdaftar di bagian Pelari , di pengaturan proyek Anda.


Cuplikan layar pelari yang ditambahkan


Apakah sesederhana itu? - ya, sangat sederhana! Tidak ada lagi kesulitan dengan mendaftarkan pelari secara manual, mulai sekarang pelari akan dibuat dan dihancurkan secara otomatis.




6. Penyebaran grafik Helm dengan QBEC


Karena kami memutuskan untuk mempertimbangkan gitlab-runner bagian dari proyek kami, sekarang saatnya untuk menggambarkannya di repositori Git kami.


Kami dapat menggambarkannya sebagai komponen terpisah dari situs web , tetapi di masa mendatang kami berencana untuk menyebarkan salinan berbeda dari situs web sangat sering, tidak seperti gitlab-runner , yang akan digunakan hanya sekali untuk setiap kluster Kubernetes. Jadi mari kita inisialisasi aplikasi terpisah untuk itu:


 cd deploy qbec init gitlab-runner cd gitlab-runner 

Kali ini kami tidak akan menjelaskan entitas Kubernetes secara manual, tetapi mengambil grafik Helm yang sudah jadi. Salah satu keuntungan dari qbec adalah kemampuan untuk merender grafik Helm langsung dari repositori Git.


Mari kita pasang menggunakan submitule git:


 git submodule add https://gitlab.com/gitlab-org/charts/gitlab-runner vendor/gitlab-runner 

Sekarang direktori vendor / gitlab-runner berisi repositori kami dengan bagan untuk gitlab-runner.


Demikian pula, Anda dapat menghubungkan repositori lain, misalnya, seluruh repositori dengan grafik resmi https://github.com/helm/charts

Mari kita gambarkan komponen / komponen gitlab-runner.jsonnet :


 local env = { name: std.extVar('qbec.io/env'), namespace: std.extVar('qbec.io/defaultNs'), }; local p = import '../params.libsonnet'; local params = p.components.gitlabRunner; std.native('expandHelmTemplate')( '../vendor/gitlab-runner', params.values, { nameTemplate: params.name, namespace: env.namespace, thisFile: std.thisFile, verbose: true, } ) 

Argumen pertama untuk memperluasHelmTemplate kita melewati jalur ke bagan, lalu params.values , yang kita ambil dari parameter lingkungan, lalu objek dengan


  • nameTemplate - nama rilis
  • namespace - namespace diteruskan ke helm
  • thisFile - diperlukan parameter yang meneruskan jalur ke file saat ini
  • verbose - menunjukkan perintah templat helm dengan semua argumen saat merender bagan

Sekarang kita akan menjelaskan parameter untuk komponen kita di lingkungan / base.libsonnet :


 local secrets = import '../secrets/base.libsonnet'; { components: { gitlabRunner: { name: 'gitlab-runner', values: { gitlabUrl: 'https://gitlab.com/', rbac: { create: true, }, runnerRegistrationToken: secrets.runnerRegistrationToken, }, }, }, } 

Perhatikan runnerRegistrationToken yang kita ambil dari file eksternal secret / base.libsonnet , mari kita buat:


 { runnerRegistrationToken: 'yga8y-jdCusVDn_t4Wxc', } 

Periksa apakah semuanya berfungsi:


 qbec show default 

jika semuanya beres, maka kami dapat menghapus rilis kami sebelumnya melalui rilis Helm:


 helm uninstall gitlab-runner 

dan menyebarkannya, tetapi sudah melalui qbec:


 qbec apply default 



7. Memperkenalkan git-crypt


Git-crypt adalah alat yang memungkinkan Anda mengatur enkripsi transparan untuk repositori Anda.


Saat ini, struktur direktori kami untuk gitlab-runner terlihat seperti ini:


 . ├── components │  ├── gitlab-runner.jsonnet ├── environments │  ├── base.libsonnet │  └── default.libsonnet ├── params.libsonnet ├── qbec.yaml ├── secrets │  └── base.libsonnet └── vendor └── gitlab-runner (submodule) 

Tapi menyimpan rahasia di Git tidak aman, kan? Jadi kita perlu mengenkripsi mereka dengan benar.


Biasanya demi satu variabel ini tidak selalu masuk akal. Anda dapat meneruskan rahasia ke qbec dan melalui variabel lingkungan sistem CI Anda.
Tetapi perlu dicatat bahwa ada proyek yang lebih kompleks yang dapat mengandung lebih banyak rahasia, akan sangat sulit untuk mentransfer semuanya melalui variabel lingkungan.

Selain itu, dalam hal ini, saya tidak akan bisa memberi tahu Anda tentang alat luar biasa seperti git-crypt .

git-crypt juga nyaman karena memungkinkan Anda untuk menyimpan seluruh sejarah rahasia, serta membandingkan, menggabungkan dan menyelesaikan konflik dengan cara yang sama seperti yang biasa kita lakukan dalam kasus Git.

Pertama-tama, setelah menginstal git-crypt, kita perlu membuat kunci untuk repositori kita:


 git crypt init 

Jika Anda memiliki kunci PGP, maka Anda dapat segera menambahkan diri Anda sebagai kolaborator untuk proyek ini:


 git-crypt add-gpg-user kvapss@gmail.com 

Dengan demikian, Anda selalu dapat mendekripsi repositori ini menggunakan kunci pribadi Anda.


Jika Anda tidak memiliki kunci PGP dan tidak diharapkan, maka Anda dapat pergi ke arah lain dan mengekspor kunci proyek:


 git crypt export-key /path/to/keyfile 

Dengan cara ini, siapa pun dengan keyfile yang diekspor akan dapat mendekripsi repositori Anda.


Sekarang saatnya untuk mengatur rahasia pertama kami.
Biarkan saya mengingatkan Anda bahwa kami masih dalam direktori deploy / gitlab-runner / , di mana kami memiliki rahasia / direktori, mari mengenkripsi semua file di dalamnya, untuk ini kami membuat file rahasia / .gitributributes dengan konten berikut:


 * filter=git-crypt diff=git-crypt .gitattributes !filter !diff 

Seperti yang Anda lihat dari konten, semua file dengan mask * akan dijalankan melalui git-crypt , kecuali untuk .gitattributes sendiri


Kami dapat memverifikasi ini dengan menjalankan:


 git crypt status -e 

Pada output, kita mendapatkan daftar semua file di repositori yang enkripsi diaktifkan


Itu saja, sekarang kita bisa melakukan perubahan dengan aman:


 cd ../.. git add . git commit -m "Add deploy for gitlab-runner" 

Untuk memblokir repositori, cukup lakukan:


 git crypt lock 

dan kemudian semua file terenkripsi berubah menjadi sesuatu biner, tidak mungkin untuk membacanya.
Untuk mendekripsi repositori, lakukan:


 git crypt unlock 



8. Buat gambar toolbox


Gambar toolbox adalah gambar seperti itu dengan semua alat yang akan kami gunakan untuk menggunakan proyek kami. Ini akan digunakan oleh gitlab runner untuk melakukan tugas-tugas penyebaran yang khas.


Semuanya sederhana di sini, kami membuat dockerfiles / toolbox / Dockerfile baru dengan konten berikut:


 FROM alpine:3.11 RUN apk add --no-cache git git-crypt RUN QBEC_VER=0.10.3 \ && wget -O- https://github.com/splunk/qbec/releases/download/v${QBEC_VER}/qbec-linux-amd64.tar.gz \ | tar -C /tmp -xzf - \ && mv /tmp/qbec /tmp/jsonnet-qbec /usr/local/bin/ RUN KUBECTL_VER=1.17.0 \ && wget -O /usr/local/bin/kubectl \ https://storage.googleapis.com/kubernetes-release/release/v${KUBECTL_VER}/bin/linux/amd64/kubectl \ && chmod +x /usr/local/bin/kubectl RUN HELM_VER=3.0.2 \ && wget -O- https://get.helm.sh/helm-v${HELM_VER}-linux-amd64.tar.gz \ | tar -C /tmp -zxf - \ && mv /tmp/linux-amd64/helm /usr/local/bin/helm 

Seperti yang Anda lihat, pada gambar ini kami memasang semua utilitas yang kami gunakan untuk menggunakan aplikasi kami. Kami tidak perlu kubectl di sini , tetapi Anda mungkin ingin bermain dengannya di tahap penyiapan pipa.


Juga, untuk dapat berkomunikasi dengan Kubernetes dan melakukan penyebaran ke dalamnya, kita perlu mengkonfigurasi peran untuk pod yang dihasilkan oleh gitlab-runner.


Untuk melakukan ini, buka direktori dengan gitlab-runner:


 cd deploy/gitlab-runner 

dan tambahkan komponen komponen baru / rbac.jsonnet :


 local env = { name: std.extVar('qbec.io/env'), namespace: std.extVar('qbec.io/defaultNs'), }; local p = import '../params.libsonnet'; local params = p.components.rbac; [ { apiVersion: 'v1', kind: 'ServiceAccount', metadata: { labels: { app: params.name, }, name: params.name, }, }, { apiVersion: 'rbac.authorization.k8s.io/v1', kind: 'Role', metadata: { labels: { app: params.name, }, name: params.name, }, rules: [ { apiGroups: [ '*', ], resources: [ '*', ], verbs: [ '*', ], }, ], }, { apiVersion: 'rbac.authorization.k8s.io/v1', kind: 'RoleBinding', metadata: { labels: { app: params.name, }, name: params.name, }, roleRef: { apiGroup: 'rbac.authorization.k8s.io', kind: 'Role', name: params.name, }, subjects: [ { kind: 'ServiceAccount', name: params.name, namespace: env.namespace, }, ], }, ] 

Kami juga akan menjelaskan parameter baru di lingkungan / base.libsonnet , yang sekarang terlihat seperti ini:


 local secrets = import '../secrets/base.libsonnet'; { components: { gitlabRunner: { name: 'gitlab-runner', values: { gitlabUrl: 'https://gitlab.com/', rbac: { create: true, }, runnerRegistrationToken: secrets.runnerRegistrationToken, runners: { serviceAccountName: $.components.rbac.name, image: 'registry.gitlab.com/kvaps/docs.example.org/toolbox:v0.0.1', }, }, }, rbac: { name: 'gitlab-runner-deploy', }, }, } 

Catatan $ .components.rbac.name mengacu pada nama untuk komponen rbac


Mari kita periksa apa yang telah berubah:


 qbec diff default 

dan terapkan perubahan kami pada Kubernetes:


 qbec apply default 

Juga jangan lupa untuk melakukan perubahan pada git:


 cd ../.. git add dockerfiles/toolbox git commit -m "Add Dockerfile for toolbox" git add deploy/gitlab-runner git commit -m "Configure gitlab-runner to use toolbox" 



9. Jalur pipa pertama kami dan perakitan gambar dengan tag


Di root proyek kami akan membuat .gitlab-ci.yml dengan konten berikut:


 .build_docker_image: stage: build image: name: gcr.io/kaniko-project/executor:debug-v0.15.0 entrypoint: [""] before_script: - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json build_toolbox: extends: .build_docker_image script: - /kaniko/executor --cache --context $CI_PROJECT_DIR/dockerfiles/toolbox --dockerfile $CI_PROJECT_DIR/dockerfiles/toolbox/Dockerfile --destination $CI_REGISTRY_IMAGE/toolbox:$CI_COMMIT_TAG only: refs: - tags build_website: extends: .build_docker_image variables: GIT_SUBMODULE_STRATEGY: normal script: - /kaniko/executor --cache --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/dockerfiles/website/Dockerfile --destination $CI_REGISTRY_IMAGE/website:$CI_COMMIT_TAG only: refs: - tags 

Harap perhatikan bahwa kami menggunakan GIT_SUBMODULE_STRATEGY: normal untuk pekerjaan-pekerjaan di mana Anda perlu menginisialisasi submodul secara eksplisit sebelum dieksekusi.


Jangan lupa untuk melakukan perubahan kami:


 git add .gitlab-ci.yml git commit -m "Automate docker build" 

Saya pikir Anda dapat dengan aman menyebutnya versi v0.0.1 dan menggantung tag:


 git tag v0.0.1 

Kami akan menggantung tag setiap kali kami perlu merilis versi baru. Tag dalam gambar Docker akan diikat ke tag Git. Setiap dorongan dengan tag baru akan menginisialisasi perakitan gambar dengan tag ini.


Jalankan git push --tags , dan lihat pipa pertama kami:


Cuplikan layar pipa pertama


Anda perlu memperhatikan fakta bahwa perakitan dengan tag cocok untuk merakit gambar buruh pelabuhan, tetapi tidak cocok untuk menggunakan aplikasi di Kubernetes. Karena tag baru juga dapat ditetapkan untuk komit lama, dalam hal ini inisialisasi pipa untuknya akan mengarah ke penyebaran versi lama.

Untuk mengatasi masalah ini, biasanya rakitan gambar buruh pelabuhan dilampirkan ke tag, dan penyebaran aplikasi ke cabang master , di mana versi gambar yang dikumpulkan di-hardcode. Dalam hal ini Anda dapat menginisialisasi rollback dengan tag master revert sederhana.



10. Otomatisasi penyebaran


Agar Gitlab-runner dapat mendekripsi rahasia kita, kita perlu mengekspor kunci repositori, dan menambahkannya ke variabel lingkungan CI kita:


 git crypt export-key /tmp/docs-repo.key base64 -w0 /tmp/docs-repo.key; echo 

simpan string yang dihasilkan di Gitlab, untuk ini kita akan pergi ke pengaturan proyek kami:
Pengaturan -> CI / CD -> Variabel


:


TypeKeyValueProtectedMaskedScope
FileGITCRYPT_KEY<your string>true ( false )trueAll environments


.gitlab-ci.yml :


 .deploy_qbec_app: stage: deploy only: refs: - master deploy_gitlab_runner: extends: .deploy_qbec_app variables: GIT_SUBMODULE_STRATEGY: normal before_script: - base64 -d "$GITCRYPT_KEY" | git-crypt unlock - script: - qbec apply default --root deploy/gitlab-runner --force:k8s-context __incluster__ --wait --yes deploy_website: extends: .deploy_qbec_app script: - qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yes 

qbec:


  • --root some/app
  • --force:k8s-context __incluster__ — , gtilab-runner. , qbec Kubernetes- kubeconfig
  • --wait — qbec , Ready exit-code.
  • --yesAre you sure? .

:


 git add .gitlab-ci.yml git commit -m "Automate deploy" 

git push :





11. push master


, . digest master-.


: website push master , Kubernetes.


.gitlab-ci.yml :


 build_website: extends: .build_docker_image variables: GIT_SUBMODULE_STRATEGY: normal script: - mkdir -p $CI_PROJECT_DIR/artifacts - /kaniko/executor --cache --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/dockerfiles/website/Dockerfile --destination $CI_REGISTRY_IMAGE/website:$CI_COMMIT_REF_NAME --digest-file $CI_PROJECT_DIR/artifacts/website.digest artifacts: paths: - artifacts/ only: refs: - master - tags deploy_website: extends: .deploy_qbec_app script: - DIGEST="$(cat artifacts/website.digest)" - qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST" 

, master refs build_website $CI_COMMIT_REF_NAME $CI_COMMIT_TAG , Git . , , docker-registry.


docker- , Kubernetes, , .


--vm:ext-str digest="$DIGEST" qbec — jsonnet. . , , , .


Kaniko digest ( --digest-file )
.


deploy/website/environments/base.libsonnet :


 { components: { website: { name: 'example-docs', image: 'registry.gitlab.com/kvaps/docs.example.org/website@' + std.extVar('digest'), replicas: 1, containerPort: 80, servicePort: 80, nodeSelector: {}, tolerations: [], ingressClass: 'nginx', domain: 'docs.example.org', }, }, } 

, master docker- website , Kubernetes.


:


 git add . git commit -m "Configure dynamic build" 

, git push - :


master


gitlab-runner push, , , , .gitlab-ci.yml :


 deploy_gitlab_runner: extends: .deploy_qbec_app variables: GIT_SUBMODULE_STRATEGY: normal before_script: - base64 -d "$GITCRYPT_KEY" | git-crypt unlock - script: - qbec apply default --root deploy/gitlab-runner --force:k8s-context __incluster__ --wait --yes only: changes: - deploy/gitlab-runner/**/* 

changes deploy/gitlab-runner/


:


 git add .gitlab-ci.yml git commit -m "Reduce gitlab-runner deploy" 

git push , - :





12. Dynamic environments


.


build_website .gitlab-ci.yml , only , Gitlab :


 build_website: extends: .build_docker_image variables: GIT_SUBMODULE_STRATEGY: normal script: - mkdir -p $CI_PROJECT_DIR/artifacts - /kaniko/executor --cache --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/dockerfiles/website/Dockerfile --destination $CI_REGISTRY_IMAGE/website:$CI_COMMIT_REF_NAME --digest-file $CI_PROJECT_DIR/artifacts/website.digest artifacts: paths: - artifacts/ 

deploy_website , environment :


 deploy_website: extends: .deploy_qbec_app environment: name: prod url: https://docs.example.org script: - DIGEST="$(cat artifacts/website.digest)" - qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST" 

Gitlab prod .


:


 deploy_website: extends: .deploy_qbec_app environment: name: prod url: https://docs.example.org script: - DIGEST="$(cat artifacts/website.digest)" - qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST" deploy_review: extends: .deploy_qbec_app environment: name: review/$CI_COMMIT_REF_NAME url: http://$CI_ENVIRONMENT_SLUG.docs.example.org on_stop: stop_review script: - DIGEST="$(cat artifacts/website.digest)" - qbec apply review --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST" --vm:ext-str subdomain="$CI_ENVIRONMENT_SLUG" --app-tag "$CI_ENVIRONMENT_SLUG" only: refs: - branches except: refs: - master stop_review: extends: .deploy_qbec_app environment: name: review/$CI_COMMIT_REF_NAME action: stop stage: deploy before_script: - git clone "$CI_REPOSITORY_URL" master - cd master script: - qbec delete review --root deploy/website --force:k8s-context __incluster__ --yes --vm:ext-str digest="$DIGEST" --vm:ext-str subdomain="$CI_ENVIRONMENT_SLUG" --app-tag "$CI_ENVIRONMENT_SLUG" variables: GIT_STRATEGY: none only: refs: - branches except: refs: - master when: manual 

push master preview .


qbec: --app-tag — , Kubernetes qbec .
review, .


qbec apply review , qbec apply default — (review default):


review deploy/website/qbec.yaml


 spec: environments: review: defaultNamespace: docs server: https://kubernetes.example.org:8443 

deploy/website/params.libsonnet :


 local env = std.extVar('qbec.io/env'); local paramsMap = { _: import './environments/base.libsonnet', default: import './environments/default.libsonnet', review: import './environments/review.libsonnet', }; if std.objectHas(paramsMap, env) then paramsMap[env] else error 'environment ' + env + ' not defined in ' + std.thisFile 

deploy/website/environments/review.libsonnet :


 // this file has the param overrides for the default environment local base = import './base.libsonnet'; local slug = std.extVar('qbec.io/tag'); local subdomain = std.extVar('subdomain'); base { components+: { website+: { name: 'example-docs-' + slug, domain: subdomain + '.docs.example.org', }, }, } 

stop_review , gitlab checkout GIT_STRATEGY: none , master - review .
, .
review , .


:


 git add . git commit -m "Enable automatic review" 

git push , git checkout -b test , git push origin test , :


environments Gitlab


? — , : git checkout master , git push origin :test , environment .


, , .gitlab-ci.yml .
protected-, master , .



13. Review Apps


Review Apps , .


, .gitlab/route-map.yml , :


 # Indices - source: /content\/(.+?)_index\.(md|html)/ public: '\1' # Pages - source: /content\/(.+?)\.(md|html)/ public: '\1/' 

:


 git add .gitlab/ git commit -m "Enable review apps" 

git push , :


Review App


Job is done!


:



, gambar

Source: https://habr.com/ru/post/id481662/


All Articles