Mencoba alat baru untuk membangun dan mengotomatiskan penerapan di Kubernetes

Mencoba alat baru untuk membangun dan mengotomatiskan penerapan di Kubernetes

Halo! Baru-baru ini, banyak alat otomatisasi keren telah dirilis baik untuk membuat image Docker maupun untuk diterapkan ke Kubernetes. Dalam hal ini, saya memutuskan untuk bermain-main dengan GitLab, mempelajari kemampuannya secara menyeluruh dan, tentu saja, menyiapkan pipeline.

Karya ini terinspirasi oleh website kubernetes.io, yang dihasilkan dari kode sumber secara otomatis, dan untuk setiap permintaan kumpulan yang dikirim, robot secara otomatis membuat versi pratinjau situs dengan perubahan Anda dan menyediakan tautan untuk dilihat.

Saya mencoba membangun proses serupa dari awal, tetapi sepenuhnya dibangun di atas Gitlab CI dan alat gratis yang biasa saya gunakan untuk menerapkan aplikasi ke Kubernetes. Hari ini saya akhirnya akan bercerita lebih banyak tentang mereka.

Artikel ini akan membahas alat-alat seperti:
Hugo, qbec, kaniko, git-crypt и GitLab CI dengan penciptaan lingkungan yang dinamis.

Isi

  1. Temui Hugo
  2. Mempersiapkan Dockerfile
  3. Mengenal kaniko
  4. Mengenal qbec
  5. Mencoba Gitlab-runner dengan Kubernetes-executor
  6. Menerapkan grafik Helm dengan qbec
  7. Memperkenalkan git-crypt
  8. Membuat gambar kotak alat
  9. Saluran pipa pertama kami dan perakitan gambar berdasarkan tag
  10. Otomatisasi penerapan
  11. Artefak dan perakitan saat mendorong ke master
  12. Lingkungan yang dinamis
  13. Tinjau Aplikasi

1. Mengenal Hugo

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

Bagi yang belum familiar dengan generator statis, saya akan bercerita lebih banyak tentangnya. Tidak seperti mesin situs web konvensional dengan database dan beberapa PHP, yang, ketika diminta oleh pengguna, menghasilkan halaman dengan cepat, generator statis dirancang sedikit berbeda. Mereka memungkinkan Anda mengambil sumber, biasanya sekumpulan file dalam markup penurunan harga dan templat tema, lalu mengkompilasinya menjadi situs web yang sepenuhnya selesai.

Artinya, sebagai hasilnya, Anda akan menerima struktur direktori dan sekumpulan file HTML yang dihasilkan, yang dapat Anda unggah ke hosting murah mana pun dan mendapatkan situs web yang berfungsi.

Anda dapat menginstal Hugo secara lokal dan mencobanya:

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 agar sesuatu dapat muncul di dalamnya, pertama-tama kami perlu menghubungkan sebuah tema; tema hanyalah sekumpulan templat dan aturan tertentu yang digunakan untuk membuat situs kami.

Untuk tema yang akan kita gunakan Mempelajari, yang menurut saya sangat cocok untuk situs dokumentasi.

Saya ingin memberikan perhatian khusus pada fakta bahwa kita tidak perlu menyimpan file tema di repositori proyek kita; sebagai gantinya, kita cukup menghubungkannya menggunakan submodul git:

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

Dengan demikian, repositori kami hanya akan berisi file yang terkait langsung dengan proyek kami, dan tema yang terhubung akan tetap menjadi tautan ke repositori tertentu dan komit di dalamnya, yaitu selalu dapat ditarik dari sumber aslinya dan tidak perlu takut. perubahan yang tidak kompatibel.

Mari kita perbaiki konfigurasinya config.toml:

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 alamatnya http://localhost:1313/ periksa situs web kami yang baru dibuat, semua perubahan yang dilakukan pada direktori secara otomatis memperbarui halaman terbuka di browser, sangat nyaman!

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

# My docs site

## Welcome to the docs!

You will be very smart :-)

Tangkapan layar halaman yang baru dibuat

Mencoba alat baru untuk membangun dan mengotomatiskan penerapan di Kubernetes

Untuk membuat situs, jalankan saja:

hugo

Isi direktori publik/ dan akan menjadi situs web Anda.
Iya ngomong-ngomong, ayo segera tambahkan .gitignore:

echo /public > .gitignore

Jangan lupa untuk melakukan perubahan kami:

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

2. Mempersiapkan Dockerfile

Saatnya menentukan struktur repositori kita. Saya biasanya menggunakan sesuatu seperti:

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

  • file buruh pelabuhan/ — berisi direktori dengan Dockerfiles dan semua yang diperlukan untuk membangun image Docker kami.
  • menyebarkan/ — berisi direktori untuk menyebarkan aplikasi kita ke Kubernetes

Jadi, kita akan membuat Dockerfile pertama kita di sepanjang jalurnya dockerfiles/situs web/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 DARI, fitur ini disebut pembangunan multi-tahap dan memungkinkan Anda mengecualikan semua yang tidak perlu dari image Docker akhir.
Dengan demikian, gambar akhir hanya akan berisi httpd gelap (server HTTP ringan) dan publik/ — konten situs web kami yang dibuat secara statis.

Jangan lupa untuk melakukan perubahan kami:

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

3. Mengenal Kaniko

Sebagai pembuat gambar buruh pelabuhan, saya memutuskan untuk menggunakan kaniko, karena pengoperasiannya tidak memerlukan daemon buruh pelabuhan, dan pembuatannya sendiri dapat dilakukan di mesin mana pun dan cache dapat disimpan langsung di registri, sehingga menghilangkan kebutuhan untuk memiliki penyimpanan persisten yang lengkap.

Untuk membangun image, jalankan saja containernya pelaksana kaniko dan berikan konteks pembangunan saat ini; ini juga dapat dilakukan 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

Где registry.gitlab.com/kvaps/docs.example.org/website — nama gambar buruh pelabuhan Anda; setelah dibuat, gambar tersebut akan secara otomatis diluncurkan ke dalam registri buruh pelabuhan.

Parameter --cache memungkinkan Anda untuk melakukan cache lapisan di registri buruh pelabuhan; sebagai contoh yang diberikan, lapisan tersebut akan disimpan registry.gitlab.com/kvaps/docs.example.org/website/cache, tetapi Anda dapat menentukan jalur lain menggunakan parameter tersebut --cache-repo.

Tangkapan layar dari registrasi buruh pelabuhan

Mencoba alat baru untuk membangun dan mengotomatiskan penerapan di Kubernetes

4. Mengenal qbec

Qbec adalah alat penerapan yang memungkinkan Anda mendeskripsikan manifes aplikasi Anda secara deklaratif dan menerapkannya ke Kubernetes. Menggunakan Jsonnet sebagai sintaks utama memungkinkan Anda menyederhanakan deskripsi perbedaan di berbagai lingkungan, dan juga hampir sepenuhnya menghilangkan pengulangan kode.

Hal ini terutama berlaku jika Anda perlu menyebarkan aplikasi ke beberapa cluster dengan parameter berbeda dan ingin mendeskripsikannya secara deklaratif di Git.

Qbec juga memungkinkan Anda merender diagram Helm dengan meneruskan parameter yang diperlukan dan kemudian mengoperasikannya dengan cara yang sama seperti manifes biasa, termasuk Anda dapat menerapkan berbagai mutasi pada grafik tersebut, dan ini, pada gilirannya, memungkinkan Anda menghilangkan kebutuhan untuk gunakan ChartMuseum. Artinya, Anda dapat menyimpan dan merender grafik langsung dari git, di tempatnya.

Seperti yang saya katakan sebelumnya, kami akan menyimpan semua penerapan dalam sebuah direktori menyebarkan/:

mkdir deploy
cd deploy

Mari kita 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

mari kita lihat filenya 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 spesifikasi.lingkungan, qbec telah membuat lingkungan default untuk kita dan mengambil alamat server, serta namespace dari kubeconfig kita saat ini.
Sekarang saat diterapkan ke kegagalan lingkungan, qbec akan selalu diterapkan hanya ke cluster Kubernetes yang ditentukan dan ke namespace yang ditentukan, artinya, Anda tidak lagi harus beralih antara konteks dan namespace untuk melakukan penerapan.
Jika perlu, Anda selalu dapat memperbarui pengaturan di file ini.

Semua lingkungan Anda dijelaskan dalam qbec.yaml, dan di dalam file params.libsonnet, yang menyatakan di mana mendapatkan parameternya.

Selanjutnya kita melihat dua direktori:

  • komponen / — semua manifes untuk aplikasi kita akan disimpan di sini; mereka dapat dijelaskan dalam file jsonnet dan yaml biasa
  • lingkungan/ — di sini kami akan menjelaskan semua variabel (parameter) untuk lingkungan kami.

Secara default kami memiliki dua file:

  • lingkungan/base.libsonnet - itu akan berisi parameter umum untuk semua lingkungan
  • lingkungan/default.libsonnet — berisi parameter yang diganti untuk lingkungan kegagalan

Mari buka lingkungan/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',
    },
  },
}

Mari kita juga membuat komponen pertama kita komponen/situs web.jsonnet:

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 mendeskripsikan tiga entitas Kubernetes sekaligus, yaitu: Penyebaran, Pelayanan и Jalan masuk. Jika kita mau, kita bisa memasukkannya ke dalam komponen yang berbeda, tapi pada tahap ini satu saja sudah cukup bagi kita.

sintaksis jsonnet sangat mirip dengan json biasa, pada prinsipnya json reguler sudah merupakan jsonnet yang valid, jadi pada awalnya mungkin akan lebih mudah bagi Anda untuk menggunakan layanan online seperti yaml2json untuk mengubah yaml biasa menjadi json, atau, jika komponen Anda tidak mengandung variabel apa pun, maka komponen tersebut dapat dijelaskan dalam bentuk yaml biasa.

Saat bekerja dengan jsonnet Saya sangat merekomendasikan memasang plugin untuk editor Anda

Misalnya ada plugin untuk vim vim-jsonnet, yang mengaktifkan penyorotan sintaksis dan dijalankan secara otomatis jsonnet fmt setiap kali Anda menyimpan (membutuhkan jsonnet diinstal).

Semuanya sudah siap, sekarang kita bisa mulai menerapkan:

Untuk melihat apa yang kita dapatkan, mari kita jalankan:

qbec show default

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

Bagus, sekarang terapkan:

qbec apply default

Pada output Anda akan selalu melihat apa yang akan dilakukan di cluster Anda, qbec akan meminta Anda untuk menyetujui perubahan dengan mengetik y Anda akan dapat mengkonfirmasi niat Anda.

Aplikasi kita sudah siap dan diterapkan!

Jika Anda membuat perubahan, Anda selalu dapat melakukan:

qbec diff default

untuk melihat bagaimana perubahan ini akan memengaruhi penerapan 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

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

Namun seperti yang ditunjukkan oleh praktik, opsi ini bukanlah yang paling ideal, baik dari segi kepraktisan maupun keamanan. Jauh lebih baik dan secara ideologis lebih tepat untuk menempatkan pelari terpisah untuk setiap proyek, atau bahkan untuk setiap lingkungan.

Untungnya, ini bukan masalah sama sekali, karena sekarang kami akan menerapkannya pelari gitlab langsung sebagai bagian dari proyek kami tepat di Kubernetes.

Gitlab menyediakan diagram kemudi siap pakai untuk menerapkan gitlab-runner ke Kubernetes. Jadi yang perlu Anda lakukan hanyalah mencari tahu tanda pendaftaran untuk proyek kami di Pengaturan -> CI / CD -> Pelari dan meneruskannya ke kemudi:

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 — alamat server Gitlab Anda.
  • yga8y-jdCusVDn_t4Wxc — token pendaftaran untuk proyek Anda.
  • rbac.create=benar — memberi pelari sejumlah hak istimewa yang diperlukan agar dapat membuat pod untuk melakukan tugas kita menggunakan kubernetes-executor.

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

Tangkapan layar pelari yang ditambahkan

Mencoba alat baru untuk membangun dan mengotomatiskan penerapan di Kubernetes

Apakah sesederhana itu? - ya, sesederhana itu! Tidak perlu lagi repot mendaftarkan pelari secara manual, mulai sekarang pelari akan dibuat dan dimusnahkan secara otomatis.

6. Terapkan grafik Helm dengan QBEC

Karena kami memutuskan untuk mempertimbangkan pelari gitlab bagian dari proyek kita, saatnya menjelaskannya di repositori Git kita.

Kita dapat menggambarkannya sebagai komponen terpisah situs web, namun di masa depan kami berencana untuk menyebarkan salinan yang berbeda situs web sangat sering, tidak seperti pelari gitlab, yang hanya akan di-deploy satu kali per cluster Kubernetes. Jadi mari kita inisialisasi aplikasi terpisah untuk itu:

cd deploy
qbec init gitlab-runner
cd gitlab-runner

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

Mari kita sambungkan menggunakan submodul git:

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

Sekarang direktorinya vendor/gitlab-pelari Kami memiliki repositori dengan grafik untuk gitlab-runner.

Dengan cara yang sama, Anda dapat menghubungkan repositori lain, misalnya seluruh repositori dengan grafik resmi https://github.com/helm/charts

Mari kita jelaskan komponennya 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 perluasHelmTemplate kita melewati jalur ke grafik, lalu params.values, yang kita ambil dari parameter lingkungan, lalu munculkan objeknya

  • Templat nama — nama rilis
  • namespace — namespace ditransfer ke kemudi
  • file ini — parameter wajib yang meneruskan jalur ke file saat ini
  • bertele-tele - menunjukkan perintah templat helm dengan semua argumen saat merender grafik

Sekarang mari kita jelaskan 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,
      },
    },
  },
}

Catatan runnerRegistrationToken kami mengambil dari file eksternal rahasia/base.libsonnet, mari kita buat:

{
  runnerRegistrationToken: 'yga8y-jdCusVDn_t4Wxc',
}

Mari kita periksa apakah semuanya berfungsi:

qbec show default

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

helm uninstall gitlab-runner

dan menerapkannya dengan cara yang sama, tetapi melalui qbec:

qbec apply default

7. Pengantar 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, bukan? Jadi kita perlu mengenkripsinya dengan benar.

Biasanya, demi satu variabel, hal ini tidak selalu masuk akal. Anda dapat mentransfer rahasia ke qbec dan melalui variabel lingkungan sistem CI Anda.
Namun perlu dicatat bahwa ada juga proyek yang lebih kompleks yang dapat berisi lebih banyak rahasia; mentransfer semuanya melalui variabel lingkungan akan sangat sulit.

Terlebih lagi, dalam hal ini saya tidak akan dapat memberi tahu Anda tentang alat yang luar biasa seperti itu git-crypt.

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

Hal pertama setelah instalasi git-crypt kita perlu membuat kunci untuk repositori kita:

git crypt init

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

git-crypt add-gpg-user [email protected]

Dengan cara ini Anda selalu dapat mendekripsi repositori ini menggunakan kunci pribadi Anda.

Jika Anda tidak memiliki kunci PGP dan tidak mengharapkannya, Anda dapat menggunakan cara lain dan mengekspor kunci proyek:

git crypt export-key /path/to/keyfile

Jadi, siapapun yang sudah mengekspor file kunci akan dapat mendekripsi repositori Anda.

Saatnya menyiapkan rahasia pertama kita.
Izinkan saya mengingatkan Anda bahwa kita masih dalam direktori terapkan/gitlab-runner/, tempat kita memiliki direktori rahasia/, mari kita enkripsi semua file di dalamnya, untuk ini kita akan membuat file rahasia/.gitattributes dengan konten berikut:

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

Seperti yang bisa dilihat dari kontennya, semua file di-mask * akan didorong melalui git-crypt, kecuali sebagian besar .gitattributes

Kita dapat memeriksanya dengan menjalankan:

git crypt status -e

Outputnya akan berupa daftar semua file dalam repositori yang enkripsinya diaktifkan

Itu saja, sekarang kita dapat melakukan perubahan dengan aman:

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

Untuk memblokir repositori, jalankan saja:

git crypt lock

dan segera semua file terenkripsi akan berubah menjadi sesuatu yang biner, tidak mungkin untuk membacanya.
Untuk mendekripsi repositori, jalankan:

git crypt unlock

8. Buat gambar kotak peralatan

Gambar kotak alat adalah gambar dengan semua alat yang akan kita gunakan untuk menerapkan proyek kita. Ini akan digunakan oleh pelari Gitlab untuk melakukan tugas penerapan umum.

Semuanya sederhana di sini, mari buat yang baru dockerfiles/kotak alat/Dockerfile 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 menginstal semua utilitas yang kami gunakan untuk menyebarkan aplikasi kami. Kami tidak membutuhkannya di sini kecuali kubectl, namun Anda mungkin ingin mencobanya selama fase penyiapan alur.

Selain itu, agar dapat berkomunikasi dengan Kubernetes dan menerapkannya, kita perlu mengonfigurasi peran untuk pod yang dihasilkan oleh gitlab-runner.

Untuk melakukan ini, mari masuk ke direktori dengan gitlab-runner:

cd deploy/gitlab-runner

dan menambahkan komponen baru komponen/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.nama mengacu pada nama untuk komponen rbac

Mari kita periksa apa yang berubah:

qbec diff default

dan terapkan perubahan kami pada Kubernetes:

qbec apply default

Juga, jangan lupa untuk melakukan perubahan kami ke 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. Saluran pipa pertama kami dan perakitan gambar berdasarkan tag

Pada akar proyek yang akan kita buat .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 dicatat kami menggunakan GIT_SUBMODULE_STRATEGY: biasa untuk 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 kita dapat dengan aman menyebutnya sebagai sebuah versi v0.0.1 dan tambahkan tag:

git tag v0.0.1

Kami akan menambahkan tag kapan pun kami perlu merilis versi baru. Tag pada gambar Docker akan dikaitkan dengan tag Git. Setiap dorongan dengan tag baru akan menginisialisasi pembuatan gambar dengan tag ini.

Ayo lakukan git mendorong --tag, dan mari kita lihat pipeline pertama kita:

Tangkapan layar dari saluran pipa pertama

Mencoba alat baru untuk membangun dan mengotomatiskan penerapan di Kubernetes

Perlu diperhatikan fakta bahwa perakitan dengan tag cocok untuk membuat image buruh pelabuhan, tetapi tidak cocok untuk menerapkan aplikasi ke Kubernetes. Karena tag baru dapat ditetapkan ke penerapan lama, dalam hal ini, menginisialisasi pipeline untuk penerapan tersebut akan mengarah pada penerapan versi lama.

Untuk mengatasi masalah ini, biasanya pembuatan gambar buruh pelabuhan dikaitkan dengan tag, dan penerapan aplikasi ke cabang menguasai, di mana versi gambar yang dikumpulkan di-hardcode. Di sinilah Anda dapat menginisialisasi rollback dengan pengembalian sederhana menguasai-ranting.

10. Otomatisasi penerapan

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

Kami akan menyimpan baris yang dihasilkan di Gitlab; untuk melakukan ini, mari buka pengaturan proyek kami:
Pengaturan -> CI / CD -> Variabel

Dan mari buat variabel baru:

Tipe
kunci
Nilai
Terlindung
Masked
Cakupan

File
GITCRYPT_KEY
<your string>
true (selama pelatihan Anda bisa false)
true
All environments

Tangkapan layar dari variabel yang ditambahkan

Mencoba alat baru untuk membangun dan mengotomatiskan penerapan di Kubernetes

Sekarang mari perbarui milik kita .gitlab-ci.yml menambahkan ke dalamnya:

.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

Di sini kami telah mengaktifkan beberapa opsi baru untuk qbec:

  • --root beberapa/aplikasi — memungkinkan Anda menentukan direktori aplikasi tertentu
  • --force:k8s-konteks __incluster__ - ini adalah variabel ajaib yang mengatakan bahwa penerapan akan terjadi di cluster yang sama tempat gtilab-runner berjalan. Hal ini diperlukan karena jika tidak, qbec akan mencoba mencari server Kubernetes yang sesuai di kubeconfig Anda
  • --Tunggu — memaksa qbec untuk menunggu hingga sumber daya yang dibuatnya masuk ke status Siap dan baru kemudian keluar dengan kode keluar yang berhasil.
  • -Ya - cukup nonaktifkan shell interaktif Apakah kamu yakin ketika dikerahkan.

Jangan lupa untuk melakukan perubahan kami:

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

Dan kemudian git push kita akan melihat bagaimana aplikasi kita diterapkan:

Tangkapan layar dari alur kedua

Mencoba alat baru untuk membangun dan mengotomatiskan penerapan di Kubernetes

11. Artefak dan perakitan saat mendorong ke master

Biasanya, langkah-langkah yang dijelaskan di atas sudah cukup untuk membangun dan memberikan hampir semua layanan mikro, namun kami tidak ingin menambahkan tag setiap kali kami perlu memperbarui situs. Oleh karena itu, kami akan mengambil rute yang lebih dinamis dan menyiapkan penerapan intisari di cabang master.

Idenya sederhana: sekarang gambar kita situs web akan dibangun kembali setiap kali Anda mendorongnya menguasai, lalu secara otomatis diterapkan ke Kubernetes.

Mari perbarui kedua pekerjaan ini di kami .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"

Harap dicatat kami telah menambahkan thread menguasai к refs untuk pekerjaan build_situs web dan sekarang kami menggunakannya $CI_COMMIT_REF_NAME daripada $CI_COMMIT_TAG, yaitu, kita melepaskan ikatan dari tag di Git dan sekarang kita akan memasukkan gambar dengan nama cabang komit yang menginisialisasi pipeline. Perlu dicatat bahwa ini juga akan berfungsi dengan tag, yang memungkinkan kita menyimpan snapshot situs dengan versi tertentu di docker-registry.

Ketika nama tag buruh pelabuhan untuk versi situs yang baru tidak dapat diubah, kami masih harus menjelaskan perubahannya pada Kubernetes, jika tidak, maka aplikasi tersebut tidak akan di-deploy ulang dari gambar baru, karena tidak akan melihat perubahan apa pun di dalamnya. manifes penerapan.

Pilihan —vm:ext-str intisari=”$DIGEST” untuk qbec - memungkinkan Anda meneruskan variabel eksternal ke jsonnet. Kami ingin itu diterapkan ulang di cluster dengan setiap rilis aplikasi kami. Kami tidak dapat lagi menggunakan nama tag, yang sekarang tidak dapat diubah, karena kami harus terikat pada versi gambar tertentu dan memicu penerapan saat gambar tersebut berubah.

Disini kita akan terbantu dengan kemampuan Kaniko dalam menyimpan gambar intisari ke sebuah file (option --file intisari)
Kemudian kami akan mentransfer file ini dan membacanya pada saat penerapan.

Mari perbarui parameter untuk kita menyebarkan/situs web/lingkungan/base.libsonnet yang sekarang akan terlihat seperti ini:

{
  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',
    },
  },
}

Selesai, sekarang semua komitmen masuk menguasai menginisialisasi build image buruh pelabuhan untuk situs web, lalu terapkan ke Kubernetes.

Jangan lupa untuk melakukan perubahan kami:

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

Kami akan memeriksanya nanti git push kita akan melihat sesuatu seperti ini:

Tangkapan layar alur untuk master

Mencoba alat baru untuk membangun dan mengotomatiskan penerapan di Kubernetes

Pada prinsipnya, kita tidak perlu menerapkan ulang gitlab-runner dengan setiap dorongan, kecuali, tentu saja, tidak ada yang berubah dalam konfigurasinya, mari kita perbaiki di .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/**/*

perubahan akan memungkinkan Anda memantau perubahan terapkan/gitlab-runner/ dan akan memicu pekerjaan kita hanya jika ada

Jangan lupa untuk melakukan perubahan kami:

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

git push, itu lebih baik:

Tangkapan layar alur yang diperbarui

Mencoba alat baru untuk membangun dan mengotomatiskan penerapan di Kubernetes

12. Lingkungan yang dinamis

Saatnya mendiversifikasi saluran pipa kita dengan lingkungan yang dinamis.

Pertama, mari perbarui pekerjaannya build_situs web di kami .gitlab-ci.yml, menghapus blok darinya hanya, yang akan memaksa Gitlab untuk memicunya pada komit apa pun di cabang mana pun:

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/

Kemudian perbarui pekerjaan tersebut deploy_situs web, tambahkan blok di sana lingkungan Hidup:

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"

Ini akan memungkinkan Gitlab untuk mengasosiasikan pekerjaan tersebut melecut lingkungan dan tampilkan tautan yang benar ke sana.

Sekarang mari tambahkan dua pekerjaan lagi:

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

Mereka akan diluncurkan saat didorong ke cabang mana pun kecuali master dan akan menyebarkan versi pratinjau situs.

Kami melihat opsi baru untuk qbec: --tag-aplikasi — ini memungkinkan Anda menandai versi aplikasi yang diterapkan dan hanya bekerja dalam tag ini; saat membuat dan menghancurkan sumber daya di Kubernetes, qbec hanya akan beroperasi dengan sumber daya tersebut.
Dengan cara ini kita tidak dapat membuat lingkungan terpisah untuk setiap tinjauan, namun cukup menggunakan kembali lingkungan yang sama.

Di sini kami juga menggunakan qbec menerapkan ulasanbukannya qbec menerapkan default - inilah saatnya kami akan mencoba menjelaskan perbedaan lingkungan kami (ulasan dan default):

Ayo tambahkan ulasan lingkungan di terapkan/situs web/qbec.yaml

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

Kemudian kami akan mendeklarasikannya menyebarkan/situs web/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

Dan tuliskan parameter khusus untuk itu menyebarkan/situs web/lingkungan/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',
    },
  },
}

Mari kita lihat lebih dekat jobu stop_review, ini akan dipicu ketika cabang dihapus dan agar gitlab tidak mencoba melakukan checkout, cabang tersebut digunakan GIT_STRATEGI: tidak ada, nanti kita kloning menguasai-cabang dan hapus ulasan melaluinya.
Agak membingungkan, tapi saya belum menemukan cara yang lebih indah.
Pilihan alternatifnya adalah menyebarkan setiap ulasan ke namespace hotel, yang selalu dapat dihancurkan seluruhnya.

Jangan lupa untuk melakukan perubahan kami:

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

git push, git checkout -b tes, tes asal git push, memeriksa:

Tangkapan layar lingkungan yang dibuat di Gitlab

Mencoba alat baru untuk membangun dan mengotomatiskan penerapan di Kubernetes

Semuanya berfungsi? - bagus, hapus cabang pengujian kami: tuan git checkout, git push asal :tes, kami memeriksa apakah pekerjaan penghapusan lingkungan berfungsi tanpa kesalahan.

Di sini saya ingin segera mengklarifikasi bahwa setiap pengembang dalam suatu proyek dapat membuat cabang, ia juga dapat berubah .gitlab-ci.yml file dan akses variabel rahasia.
Oleh karena itu, sangat disarankan untuk mengizinkan penggunaannya hanya untuk cabang yang dilindungi, misalnya di menguasai, atau buat kumpulan variabel terpisah untuk setiap lingkungan.

13. Tinjau Aplikasi

Tinjau Aplikasi Ini adalah fitur GitLab yang memungkinkan Anda menambahkan tombol untuk setiap file di repositori agar dapat melihatnya dengan cepat di lingkungan yang diterapkan.

Agar tombol-tombol ini muncul, Anda perlu membuat file .gitlab/route-map.yml dan jelaskan semua transformasi jalur di dalamnya; dalam kasus kami ini akan sangat sederhana:

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

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

Jangan lupa untuk melakukan perubahan kami:

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

git push, dan cek:

Tangkapan layar tombol Tinjau Aplikasi

Mencoba alat baru untuk membangun dan mengotomatiskan penerapan di Kubernetes

Pekerjaan selesai!

Sumber proyek:

Terima kasih atas perhatian Anda, saya harap Anda menyukainya Mencoba alat baru untuk membangun dan mengotomatiskan penerapan di Kubernetes

Sumber: www.habr.com

Tambah komentar