Sinusubukan ang mga bagong tool para sa pagbuo at pag-automate ng deployment sa Kubernetes

Sinusubukan ang mga bagong tool para sa pagbuo at pag-automate ng deployment sa Kubernetes

Kamusta! Kamakailan, maraming mga cool na tool sa automation ang inilabas kapwa para sa pagbuo ng mga imahe ng Docker at para sa pag-deploy sa Kubernetes. Kaugnay nito, nagpasya akong makipaglaro sa GitLab, masusing pag-aralan ang mga kakayahan nito at, siyempre, i-set up ang pipeline.

Ang gawaing ito ay inspirasyon ng website kubernetes.io, na nabuo mula sa source code awtomatiko, at para sa bawat kahilingan sa pool na ipinadala, awtomatikong bumubuo ang robot ng preview na bersyon ng site kasama ng iyong mga pagbabago at nagbibigay ng link para sa pagtingin.

Sinubukan kong bumuo ng katulad na proseso mula sa simula, ngunit ganap na binuo sa Gitlab CI at mga libreng tool na nakasanayan kong gamitin upang mag-deploy ng mga application sa Kubernetes. Ngayon sa wakas ay sasabihin ko sa iyo ang higit pa tungkol sa kanila.

Tatalakayin ng artikulo ang mga tool tulad ng:
Hugo, qbec, kaniko, git-crypt и GitLab CI sa paglikha ng mga dynamic na kapaligiran.

Nilalaman

  1. Kilalanin si Hugo
  2. Inihahanda ang Dockerfile
  3. Pagkilala sa kaniko
  4. Pagkilala sa qbec
  5. Sinusubukan ang Gitlab-runner kasama ang Kubernetes-executor
  6. Pag-deploy ng mga Helm chart sa qbec
  7. Ipinapakilala ang git-crypt
  8. Paglikha ng larawan ng toolbox
  9. Ang aming unang pipeline at pagpupulong ng mga larawan sa pamamagitan ng mga tag
  10. Automation ng deployment
  11. Mga artifact at pagpupulong kapag nagtutulak sa master
  12. Mga dinamikong kapaligiran
  13. Suriin ang Apps

1. Pagkilala kay Hugo

Bilang halimbawa ng aming proyekto, susubukan naming lumikha ng isang site sa pag-publish ng dokumentasyon na binuo sa Hugo. Si Hugo ay isang static na content generator.

Para sa mga hindi pamilyar sa mga static generator, sasabihin ko sa iyo ang higit pa tungkol sa mga ito. Hindi tulad ng maginoo na mga makina ng website na may database at ilang PHP, na, kapag hiniling ng isang user, ay bumubuo ng mga pahina sa mabilisang, ang mga static na generator ay idinisenyo nang medyo naiiba. Nagbibigay-daan sa iyo ang mga ito na kumuha ng mga mapagkukunan, karaniwang isang set ng mga file sa Markdown markup at mga template ng tema, pagkatapos ay i-compile ang mga ito sa isang ganap na tapos na website.

Iyon ay, bilang isang resulta, makakatanggap ka ng isang istraktura ng direktoryo at isang hanay ng mga nabuong HTML file, na maaari mo lamang i-upload sa anumang murang pagho-host at makakuha ng isang gumaganang website.

Maaari mong i-install ang Hugo nang lokal at subukan ito:

Pagsisimula ng bagong site:

hugo new site docs.example.org

At sa parehong oras ang git repository:

cd docs.example.org
git init

Sa ngayon, malinis ang aming site at para may lumitaw dito, kailangan muna naming ikonekta ang isang tema; ang isang tema ay isang hanay lamang ng mga template at tinukoy na mga panuntunan kung saan nabuo ang aming site.

Para sa temang gagamitin natin Matuto, na, sa aking opinyon, ay ganap na angkop para sa isang site ng dokumentasyon.

Nais kong bigyang-pansin ang katotohanan na hindi namin kailangang i-save ang mga file ng tema sa aming imbakan ng proyekto; sa halip, maaari naming ikonekta lamang ito gamit ang git submodule:

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

Kaya, ang aming repositoryo ay maglalaman lamang ng mga file na direktang nauugnay sa aming proyekto, at ang konektadong tema ay mananatili bilang isang link sa isang partikular na imbakan at isang commit dito, iyon ay, maaari itong palaging makuha mula sa orihinal na pinagmulan at hindi matakot sa hindi tugmang mga pagbabago.

Itama natin ang config config.toml:

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

Nasa yugto na ito maaari kang tumakbo:

hugo server

At sa address http://localhost:1313/ suriin ang aming bagong likhang website, lahat ng mga pagbabagong ginawa sa direktoryo ay awtomatikong i-update ang bukas na pahina sa browser, napaka-maginhawa!

Subukan nating gumawa ng cover page sa nilalaman/_index.md:

# My docs site

## Welcome to the docs!

You will be very smart :-)

Screenshot ng bagong likhang pahina

Sinusubukan ang mga bagong tool para sa pagbuo at pag-automate ng deployment sa Kubernetes

Upang makabuo ng isang site, patakbuhin lang ang:

hugo

Mga nilalaman ng direktoryo publiko/ at magiging iyong website.
Oo nga pala, idagdag natin agad .gignignore:

echo /public > .gitignore

Huwag kalimutang i-commit ang aming mga pagbabago:

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

2. Paghahanda ng Dockerfile

Panahon na upang tukuyin ang istraktura ng aming imbakan. Karaniwan akong gumagamit ng isang bagay tulad ng:

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

  • dockerfiles/ — naglalaman ng mga direktoryo na may mga Dockerfile at lahat ng kailangan para sa pagbuo ng aming mga imahe ng Docker.
  • i-deploy/ — naglalaman ng mga direktoryo para sa pag-deploy ng aming mga application sa Kubernetes

Kaya, gagawa kami ng aming unang Dockerfile kasama ang landas 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" ]

Tulad ng nakikita mo, ang Dockerfile ay naglalaman ng dalawa MULA SA, ang pagkakataong ito ay tinatawag multi-stage build at nagbibigay-daan sa iyong ibukod ang lahat ng hindi kailangan mula sa huling larawan ng docker.
Kaya, ang huling larawan ay maglalaman lamang madilimhttpd (magaan na HTTP server) at publiko/ — ang nilalaman ng aming statically generated na website.

Huwag kalimutang i-commit ang aming mga pagbabago:

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

3. Pagkilala sa kaniko

Bilang isang tagabuo ng imahe ng docker, nagpasya akong gamitin kaniko, dahil ang operasyon nito ay hindi nangangailangan ng docker daemon, at ang build mismo ay maaaring isagawa sa anumang makina at ang cache ay maaaring maimbak nang direkta sa registry, sa gayon ay inaalis ang pangangailangan na magkaroon ng isang ganap na patuloy na imbakan.

Upang buuin ang imahe, patakbuhin lang ang lalagyan na may kanikong tagapagpatupad at ipasa ito sa kasalukuyang konteksto ng build; maaari rin itong gawin nang lokal, sa pamamagitan ng docker:

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

saan registry.gitlab.com/kvaps/docs.example.org/website — ang pangalan ng iyong docker image; pagkatapos ng pagbuo, awtomatiko itong ilulunsad sa docker registry.

Parametro --cache nagbibigay-daan sa iyo na mag-cache ng mga layer sa registry ng docker; para sa halimbawang ibinigay, mai-save ang mga ito sa registry.gitlab.com/kvaps/docs.example.org/website/cache, ngunit maaari mong tukuyin ang isa pang landas gamit ang parameter --cache-repo.

Screenshot ng docker-registry

Sinusubukan ang mga bagong tool para sa pagbuo at pag-automate ng deployment sa Kubernetes

4. Pagkilala sa qbec

Qbec ay isang tool sa pag-deploy na nagbibigay-daan sa iyong deklaratibong ilarawan ang iyong mga manifest ng application at i-deploy ang mga ito sa Kubernetes. Ang paggamit ng Jsonnet bilang pangunahing syntax ay nagbibigay-daan sa iyong lubos na pasimplehin ang paglalarawan ng mga pagkakaiba sa maraming kapaligiran, at halos ganap na inaalis ang pag-uulit ng code.

Ito ay maaaring maging totoo lalo na sa mga kaso kung saan kailangan mong mag-deploy ng isang application sa ilang mga cluster na may iba't ibang mga parameter at nais na deklaratibong ilarawan ang mga ito sa Git.

Pinapayagan ka rin ng Qbec na mag-render ng mga Helm chart sa pamamagitan ng pagpasa sa kanila ng mga kinakailangang parameter at pagkatapos ay patakbuhin ang mga ito sa parehong paraan tulad ng mga regular na manifest, kabilang ang maaari mong ilapat ang iba't ibang mga mutasyon sa kanila, at ito naman, ay nagbibigay-daan sa iyo na mapupuksa ang pangangailangan na gamitin ang ChartMuseum. Iyon ay, maaari kang mag-imbak at mag-render ng mga chart nang direkta mula sa git, kung saan sila nabibilang.

Gaya ng sinabi ko kanina, iimbak namin ang lahat ng deployment sa isang direktoryo i-deploy/:

mkdir deploy
cd deploy

Simulan natin ang ating unang aplikasyon:

qbec init website
cd website

Ngayon ang istraktura ng aming application ay ganito ang hitsura:

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

tingnan natin ang file qbec.yaml:

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

Narito kami ay pangunahing interesado sa spec.environments, nakagawa na ang qbec ng default na kapaligiran para sa amin at kinuha ang address ng server, pati na rin ang namespace mula sa aming kasalukuyang kubeconfig.
Ngayon kapag nagde-deploy sa default environment, ang qbec ay palaging magde-deploy lamang sa tinukoy na Kubernetes cluster at sa tinukoy na namespace, ibig sabihin, hindi mo na kailangang magpalipat-lipat sa pagitan ng mga konteksto at namespace para makapagsagawa ng deployment.
Kung kinakailangan, maaari mong palaging i-update ang mga setting sa file na ito.

Inilalarawan ang lahat ng iyong kapaligiran sa qbec.yaml, at sa file params.libsonnet, kung saan sinasabi nito kung saan kukunin ang mga parameter para sa kanila.

Susunod na nakikita namin ang dalawang direktoryo:

  • mga bahagi / — lahat ng mga manifest para sa aming aplikasyon ay maiimbak dito; maaari silang ilarawan pareho sa jsonnet at regular na yaml file
  • kapaligiran/ — dito namin ilalarawan ang lahat ng mga variable (parameter) para sa aming mga kapaligiran.

Bilang default, mayroon kaming dalawang file:

  • environment/base.libsonnet - maglalaman ito ng mga karaniwang parameter para sa lahat ng kapaligiran
  • environment/default.libsonnet — naglalaman ng mga parameter na na-override para sa kapaligiran default

buksan natin environment/base.libsonnet at magdagdag ng mga parameter para sa aming unang bahagi doon:

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

Gawin din natin ang ating unang bahagi component/website.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,
                },
              },
            ],
          },
        },
      ],
    },
  },
]

Sa file na ito, inilarawan namin ang tatlong entity ng Kubernetes nang sabay-sabay, ito ay: paglawak, serbisyo и Pagpasok. Kung gusto namin, maaari naming ilagay ang mga ito sa iba't ibang bahagi, ngunit sa yugtong ito ang isa ay sapat na para sa amin.

palaugnayan jsonnet ay halos kapareho sa regular na json, sa prinsipyo, ang regular na json ay may bisa na jsonnet, kaya sa una ay maaaring mas madali para sa iyo na gumamit ng mga online na serbisyo tulad ng yaml2json upang i-convert ang iyong karaniwang yaml sa json, o, kung ang iyong mga bahagi ay walang anumang mga variable, maaari silang ilarawan sa anyo ng regular na yaml.

Kapag nagtatrabaho kasama jsonnet Lubos kong inirerekumenda ang pag-install ng isang plugin para sa iyong editor

Halimbawa, mayroong isang plugin para sa vim vim-jsonnet, na ino-on ang pag-highlight ng syntax at awtomatikong ipapatupad jsonnet fmt sa tuwing magse-save ka (nangangailangan ng naka-install na jsonnet).

Handa na ang lahat, maaari na tayong magsimulang mag-deploy:

Upang makita kung ano ang nakuha namin, tumakbo tayo:

qbec show default

Sa output, makikita mo ang mga nai-render na yaml na manifest na ilalapat sa default na cluster.

Mahusay, mag-apply ngayon:

qbec apply default

Sa output palagi mong makikita kung ano ang gagawin sa iyong cluster, hihilingin sa iyo ng qbec na sumang-ayon sa mga pagbabago sa pamamagitan ng pag-type y magagawa mong kumpirmahin ang iyong mga intensyon.

Ang aming aplikasyon ay handa at na-deploy na!

Kung gagawa ka ng mga pagbabago, magagawa mo palagi:

qbec diff default

upang makita kung paano makakaapekto ang mga pagbabagong ito sa kasalukuyang deployment

Huwag kalimutang i-commit ang aming mga pagbabago:

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

5. Sinusubukan ang Gitlab-runner sa Kubernetes-executor

Until recently regular lang ang gamit ko gitlab-runner sa isang pre-prepared machine (LXC container) na may shell o docker-executor. Sa una, mayroon kaming ilang ganoong mga runner sa buong mundo na tinukoy sa aming gitlab. Nangolekta sila ng mga larawan ng docker para sa lahat ng proyekto.

Ngunit tulad ng ipinakita ng kasanayan, ang pagpipiliang ito ay hindi ang pinaka-perpekto, kapwa sa mga tuntunin ng pagiging praktiko at kaligtasan. Mas mabuti at mas tama sa ideolohiya na magkaroon ng hiwalay na mga runner na naka-deploy para sa bawat proyekto, o kahit para sa bawat kapaligiran.

Sa kabutihang palad, ito ay hindi isang problema sa lahat, dahil ngayon kami ay i-deploy gitlab-runner direkta bilang bahagi ng aming proyekto sa Kubernetes mismo.

Nagbibigay ang Gitlab ng isang handa na helm chart para sa pag-deploy ng gitlab-runner sa Kubernetes. Kaya ang kailangan mo lang gawin ay alamin token sa pagpaparehistro para sa aming proyekto sa Mga Setting -> CI / CD -> Mga Runner at ipasa ito sa timon:

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

Saan:

  • https://gitlab.com — ang address ng iyong Gitlab server.
  • yga8y-jdCusVDn_t4Wxc — token ng pagpaparehistro para sa iyong proyekto.
  • rbac.create=true — nagbibigay sa runner ng kinakailangang halaga ng mga pribilehiyo upang makagawa ng mga pod upang maisagawa ang aming mga gawain gamit ang kubernetes-executor.

Kung tama ang lahat, dapat mong makita ang isang nakarehistrong runner sa seksyon Runners, sa iyong mga setting ng proyekto.

Screenshot ng idinagdag na runner

Sinusubukan ang mga bagong tool para sa pagbuo at pag-automate ng deployment sa Kubernetes

Ganun ba kasimple? - oo, simple lang! Wala nang abala sa pagrerehistro ng mga runner nang manu-mano, mula ngayon ang mga runner ay malilikha at awtomatikong masisira.

6. I-deploy ang mga Helm chart sa QBEC

Since we decided to consider gitlab-runner bahagi ng aming proyekto, oras na para ilarawan ito sa aming Git repository.

Maaari naming ilarawan ito bilang isang hiwalay na bahagi website, ngunit sa hinaharap plano naming mag-deploy ng iba't ibang mga kopya website madalas, hindi katulad gitlab-runner, na isang beses lang ide-deploy sa bawat Kubernetes cluster. Kaya't simulan natin ang isang hiwalay na aplikasyon para dito:

cd deploy
qbec init gitlab-runner
cd gitlab-runner

Sa pagkakataong ito, hindi namin ilalarawan nang manu-mano ang mga entidad ng Kubernetes, ngunit kukuha ng yari na Helm chart. Isa sa mga bentahe ng qbec ay ang kakayahang mag-render ng mga Helm chart nang direkta mula sa isang Git repository.

Ikonekta natin ito gamit ang git submodule:

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

Ngayon ang direktoryo vendor/gitlab-runner Mayroon kaming repositoryo na may tsart para sa gitlab-runner.

Sa katulad na paraan, maaari mong ikonekta ang iba pang mga repositoryo, halimbawa, ang buong repositoryo na may mga opisyal na chart https://github.com/helm/charts

Ilarawan natin ang bahagi components/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,
  }
)

Ang unang argumento sa expandHelmTemplate pumasa kami sa landas patungo sa tsart, pagkatapos params.values, na kinukuha natin mula sa mga parameter ng kapaligiran, pagkatapos ay kasama ang bagay

  • nameTemplate - pamagat ng release
  • namespace — inilipat ang namespace sa timon
  • thisFile — isang kinakailangang parameter na pumasa sa landas patungo sa kasalukuyang file
  • pandiwang - nagpapakita ng utos template ng timon kasama ang lahat ng mga argumento kapag nag-render ng tsart

Ngayon ilarawan natin ang mga parameter para sa ating bahagi sa environment/base.libsonnet:

local secrets = import '../secrets/base.libsonnet';

{
  components: {
    gitlabRunner: {
      name: 'gitlab-runner',
      values: {
        gitlabUrl: 'https://gitlab.com/',
        rbac: {
          create: true,
        },
        runnerRegistrationToken: secrets.runnerRegistrationToken,
      },
    },
  },
}

Magbayad ng pansin runnerRegistrationToken kinukuha namin mula sa isang panlabas na file secrets/base.libsonnet, gawin natin ito:

{
  runnerRegistrationToken: 'yga8y-jdCusVDn_t4Wxc',
}

Suriin natin kung gumagana ang lahat:

qbec show default

kung maayos na ang lahat, maaari naming tanggalin ang dati naming na-deploy na release sa pamamagitan ng Helm:

helm uninstall gitlab-runner

at i-deploy ito sa parehong paraan, ngunit sa pamamagitan ng qbec:

qbec apply default

7. Panimula sa git-crypt

Git-crypt ay isang tool na nagbibigay-daan sa iyong mag-set up ng transparent na encryption para sa iyong repository.

Sa ngayon, ganito ang hitsura ng aming istraktura ng direktoryo para sa gitlab-runner:

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

Ngunit ang pag-iimbak ng mga lihim sa Git ay hindi ligtas, hindi ba? Kaya kailangan nating i-encrypt ang mga ito nang maayos.

Karaniwan, para sa kapakanan ng isang variable, hindi ito palaging may katuturan. Maaari kang maglipat ng mga lihim sa qbec at sa pamamagitan ng mga variable ng kapaligiran ng iyong CI system.
Ngunit nararapat na tandaan na mayroon ding mga mas kumplikadong proyekto na maaaring maglaman ng maraming higit pang mga lihim; ang paglilipat ng lahat ng ito sa pamamagitan ng mga variable ng kapaligiran ay magiging lubhang mahirap.

Bukod dito, sa kasong ito hindi ko masasabi sa iyo ang tungkol sa napakagandang tool gaya ng git-crypt.

git-crypt Maginhawa rin ito dahil pinapayagan ka nitong i-save ang buong kasaysayan ng mga lihim, pati na rin ang paghambingin, pagsasama-sama at paglutas ng mga salungatan sa parehong paraan tulad ng nakasanayan naming gawin sa kaso ng Git.

Unang bagay pagkatapos ng pag-install git-crypt kailangan naming bumuo ng mga susi para sa aming imbakan:

git crypt init

Kung mayroon kang PGP key, maaari mong agad na idagdag ang iyong sarili bilang isang collaborator para sa proyektong ito:

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

Sa ganitong paraan maaari mong palaging i-decrypt ang repository na ito gamit ang iyong pribadong key.

Kung wala kang PGP key at hindi mo ito inaasahan, maaari kang pumunta sa kabilang paraan at i-export ang project key:

git crypt export-key /path/to/keyfile

Kaya, sinuman na may na-export keyfile ay magagawang i-decrypt ang iyong imbakan.

Oras na para i-set up ang una nating sikreto.
Hayaan mong ipaalala ko sa iyo na tayo ay nasa direktoryo pa rin deploy/gitlab-runner/, kung saan mayroon kaming direktoryo mga sikreto/, i-encrypt natin ang lahat ng mga file sa loob nito, para dito gagawa tayo ng isang file mga lihim/.gitattributes na may sumusunod na nilalaman:

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

Tulad ng makikita mula sa nilalaman, ang lahat ng mga file ay naka-mask * ay madadaanan git-crypt, maliban sa karamihan .gitattributes

Maaari naming suriin ito sa pamamagitan ng pagpapatakbo:

git crypt status -e

Ang output ay isang listahan ng lahat ng mga file sa repository kung saan pinagana ang pag-encrypt

Iyon lang, ngayon ay ligtas na nating maisagawa ang ating mga pagbabago:

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

Upang harangan ang isang repositoryo, patakbuhin lang ang:

git crypt lock

at kaagad ang lahat ng naka-encrypt na file ay magiging binary na bagay, magiging imposibleng basahin ang mga ito.
Upang i-decrypt ang imbakan, patakbuhin ang:

git crypt unlock

8. Gumawa ng larawan ng toolbox

Ang imahe ng toolbox ay isang imahe na may lahat ng mga tool na gagamitin namin upang i-deploy ang aming proyekto. Gagamitin ito ng Gitlab runner para magsagawa ng mga karaniwang gawain sa pag-deploy.

Simple lang ang lahat dito, gumawa tayo ng bago dockerfiles/toolbox/Dockerfile na may sumusunod na nilalaman:

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

Tulad ng nakikita mo, sa larawang ito ay ini-install namin ang lahat ng mga utility na ginamit namin upang i-deploy ang aming application. Hindi namin ito kailangan dito maliban kung kubectl, ngunit maaaring gusto mong paglaruan ito sa panahon ng yugto ng pag-setup ng pipeline.

Gayundin, upang magawang makipag-usap sa Kubernetes at ma-deploy dito, kailangan nating mag-configure ng isang tungkulin para sa mga pod na nabuo ng gitlab-runner.

Upang gawin ito, pumunta tayo sa direktoryo na may gitlab-runner:

cd deploy/gitlab-runner

at magdagdag ng bagong bahagi component/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,
      },
    ],
  },
]

Ilalarawan din namin ang mga bagong parameter sa environment/base.libsonnet, na ngayon ay ganito ang hitsura:

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

Magbayad ng pansin $.components.rbac.name tumutukoy sa pangalan para sa sangkap rbac

Suriin natin kung ano ang nagbago:

qbec diff default

at ilapat ang aming mga pagbabago sa Kubernetes:

qbec apply default

Gayundin, huwag kalimutang i-commit ang aming mga pagbabago sa 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. Ang aming unang pipeline at pagpupulong ng mga larawan sa pamamagitan ng mga tag

Sa ugat ng proyektong gagawin natin .gitlab-ci.yml na may sumusunod na nilalaman:

.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

Mangyaring tandaan na ginagamit namin GIT_SUBMODULE_STRATEGY: normal para sa mga trabaho kung saan kailangan mong tahasang simulan ang mga submodules bago isagawa.

Huwag kalimutang i-commit ang aming mga pagbabago:

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

Sa tingin ko maaari nating ligtas na tawagan itong isang bersyon v0.0.1 at idagdag ang tag:

git tag v0.0.1

Magdaragdag kami ng mga tag sa tuwing kailangan naming maglabas ng bagong bersyon. Ang mga tag sa mga larawan ng Docker ay iuugnay sa mga tag ng Git. Ang bawat push na may bagong tag ay magsisimula sa pagbuo ng mga larawan gamit ang tag na ito.

Gawin natin git push --tags, at tingnan natin ang aming unang pipeline:

Screenshot ng unang pipeline

Sinusubukan ang mga bagong tool para sa pagbuo at pag-automate ng deployment sa Kubernetes

Ito ay nagkakahalaga ng pagguhit ng iyong pansin sa katotohanan na ang pagpupulong sa pamamagitan ng mga tag ay angkop para sa pagbuo ng mga imahe ng docker, ngunit hindi angkop para sa pag-deploy ng isang application sa Kubernetes. Dahil ang mga bagong tag ay maaaring italaga sa mga lumang commit, sa kasong ito, ang pagsisimula ng pipeline para sa mga ito ay hahantong sa pag-deploy ng lumang bersyon.

Upang malutas ang problemang ito, kadalasan ang pagbuo ng mga imahe ng docker ay nakatali sa mga tag, at ang pag-deploy ng application sa isang sangay panginoon, kung saan naka-hardcode ang mga bersyon ng mga nakolektang larawan. Ito ay kung saan maaari mong simulan ang rollback sa isang simpleng pagbabalik panginoon-mga sanga.

10. Automation ng deployment

Upang ma-decrypt ng Gitlab-runner ang aming mga lihim, kakailanganin naming i-export ang repository key at idagdag ito sa aming mga variable ng CI environment:

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

Ise-save namin ang resultang linya sa Gitlab; para magawa ito, pumunta tayo sa aming mga setting ng proyekto:
Mga Setting -> CI / CD -> Mga Variable

At gumawa tayo ng bagong variable:

uri
Key
halaga
Protected
Naka-mask
saklaw

File
GITCRYPT_KEY
<your string>
true (sa panahon ng pagsasanay maaari mong false)
true
All environments

Screenshot ng idinagdag na variable

Sinusubukan ang mga bagong tool para sa pagbuo at pag-automate ng deployment sa Kubernetes

Ngayon i-update natin ang ating .gitlab-ci.yml pagdaragdag dito:

.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

Dito pinagana namin ang ilang mga bagong opsyon para sa qbec:

  • --root some/app — nagpapahintulot sa iyo na matukoy ang direktoryo ng isang partikular na application
  • --force:k8s-context __incluster__ - isa itong magic variable na nagsasabing ang deployment ay magaganap sa parehong cluster kung saan tumatakbo ang gtilab-runner. Ito ay kinakailangan dahil kung hindi ay susubukan ng qbec na maghanap ng angkop na server ng Kubernetes sa iyong kubeconfig
  • --wait — pinipilit ang qbec na maghintay hanggang ang mga mapagkukunan na nilikha nito ay mapunta sa Ready na estado at pagkatapos ay lumabas na may matagumpay na exit-code.
  • —oo - hindi pinapagana ang interactive na shell Sigurado ka ba? kapag na-deploy.

Huwag kalimutang i-commit ang aming mga pagbabago:

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

At pagkatapos git push makikita natin kung paano na-deploy ang ating mga application:

Screenshot ng pangalawang pipeline

Sinusubukan ang mga bagong tool para sa pagbuo at pag-automate ng deployment sa Kubernetes

11. Mga artifact at pagpupulong kapag nagtutulak sa master

Karaniwan, ang mga hakbang na inilarawan sa itaas ay sapat na upang bumuo at maghatid ng halos anumang microservice, ngunit hindi namin gustong magdagdag ng tag sa tuwing kailangan naming i-update ang site. Samakatuwid, kukuha kami ng mas dynamic na ruta at magse-set up ng digest deployment sa master branch.

Ang ideya ay simple: ngayon ang imahe ng aming website ay muling itatayo sa tuwing magtutulak ka panginoon, at pagkatapos ay awtomatikong i-deploy sa Kubernetes.

I-update natin ang dalawang trabahong ito sa ating .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"

Pakitandaan na nagdagdag kami ng thread panginoon к ref para sa mga trabaho build_website at ginagamit namin ngayon $CI_COMMIT_REF_NAME sa halip ng $CI_COMMIT_TAG, ibig sabihin, hindi kami nakatali mula sa mga tag sa Git at ngayon ay itutulak namin ang isang imahe na may pangalan ng commit branch na nagpasimula ng pipeline. Kapansin-pansin na gagana rin ito sa mga tag, na magbibigay-daan sa amin na mag-save ng mga snapshot ng isang site na may partikular na bersyon sa docker-registry.

Kapag ang pangalan ng docker tag para sa isang bagong bersyon ng site ay maaaring hindi mabago, kailangan pa rin naming ilarawan ang mga pagbabago sa Kubernetes, kung hindi, hindi nito ipapatupad muli ang application mula sa bagong larawan, dahil hindi nito mapapansin ang anumang mga pagbabago sa deployment manifest.

Pagpipilian —vm:ext-str digest=”$DIGEST” para sa qbec - pinapayagan kang magpasa ng isang panlabas na variable sa jsonnet. Nais namin na sa bawat paglabas ng aming aplikasyon ay mai-redeploy ito sa cluster. Hindi na namin magagamit ang pangalan ng tag, na maaari na ngayong hindi na mababago, dahil kailangan naming itali sa isang partikular na bersyon ng larawan at i-trigger ang deployment kapag nagbago ito.

Dito tayo matutulungan ng kakayahan ni Kaniko na mag-save ng digest na imahe sa isang file (option --digest-file)
Pagkatapos ay ililipat namin ang file na ito at babasahin ito sa oras ng pag-deploy.

I-update natin ang mga parameter para sa ating deploy/website/environments/base.libsonnet na magiging ganito na ngayon:

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

Tapos na, ngayon kahit anong commit panginoon sinisimulan ang pagbuo ng docker na imahe para sa website, at pagkatapos ay i-deploy ito sa Kubernetes.

Huwag kalimutang i-commit ang aming mga pagbabago:

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

Susuriin natin mamaya git push dapat nating makita ang isang bagay tulad nito:

Screenshot ng pipeline para sa master

Sinusubukan ang mga bagong tool para sa pagbuo at pag-automate ng deployment sa Kubernetes

Sa prinsipyo, hindi natin kailangang i-redeploy ang gitlab-runner sa bawat push, maliban kung, siyempre, walang nagbago sa configuration nito, ayusin natin ito sa .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/**/*

mga pagbabago ay magbibigay-daan sa iyo na subaybayan ang mga pagbabago sa deploy/gitlab-runner/ at magti-trigger lamang sa ating trabaho kung mayroon man

Huwag kalimutang i-commit ang aming mga pagbabago:

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

git push, mas maganda iyan:

Screenshot ng na-update na pipeline

Sinusubukan ang mga bagong tool para sa pagbuo at pag-automate ng deployment sa Kubernetes

12. Mga dinamikong kapaligiran

Oras na para pag-iba-ibahin ang aming pipeline gamit ang mga dynamic na kapaligiran.

Una, i-update natin ang trabaho build_website sa aming .gitlab-ci.yml, inaalis ang block mula dito lamang, na pipilitin ang Gitlab na i-trigger ito sa anumang commit sa anumang sangay:

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/

Pagkatapos ay i-update ang trabaho deploy_website, magdagdag ng isang bloke doon kapaligiran:

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"

Papayagan nito ang Gitlab na iugnay ang trabaho sa prod kapaligiran at ipakita ang tamang link dito.

Ngayon magdagdag tayo ng dalawa pang trabaho:

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

Ilulunsad ang mga ito sa pag-push sa anumang sangay maliban sa master at ide-deploy ang preview na bersyon ng site.

Nakikita namin ang isang bagong opsyon para sa qbec: --app-tag — pinapayagan ka nitong mag-tag ng mga naka-deploy na bersyon ng application at gumana lamang sa loob ng tag na ito; kapag gumagawa at sumisira ng mga mapagkukunan sa Kubernetes, gagana lang ang qbec sa kanila.
Sa ganitong paraan hindi kami makakagawa ng hiwalay na kapaligiran para sa bawat pagsusuri, ngunit muling gamitin ang pareho.

Dito din natin ginagamit qbec ilapat ang pagsusuri, sa halip na qbec ilapat ang default - ito ang eksaktong sandali na susubukan naming ilarawan ang mga pagkakaiba para sa aming mga kapaligiran (review at default):

Dagdagan natin suriin kapaligiran sa deploy/website/qbec.yaml

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

Pagkatapos ay idedeklara namin ito 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

At isulat ang mga custom na parameter para dito 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',
    },
  },
}

Tingnan din natin ang jobu stop_review, ito ay ma-trigger kapag ang sangay ay tinanggal at upang ang gitlab ay hindi subukang mag-checkout ito ay ginagamit GIT_STRATEGY: wala, mamaya clone tayo panginoon-sangay at tanggalin ang pagsusuri sa pamamagitan nito.
Medyo nakakalito, ngunit hindi pa ako nakakahanap ng mas magandang paraan.
Ang isang alternatibong opsyon ay ang pag-deploy ng bawat review sa isang namespace ng hotel, na palaging maaaring ganap na buwagin.

Huwag kalimutang i-commit ang aming mga pagbabago:

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

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

Screenshot ng mga nilikhang kapaligiran sa Gitlab

Sinusubukan ang mga bagong tool para sa pagbuo at pag-automate ng deployment sa Kubernetes

Lahat ay gumagana? - mahusay, tanggalin ang aming sangay ng pagsubok: master ng gitout, git push pinanggalingan :test, sinusuri namin na ang mga trabaho sa pagtanggal sa kapaligiran ay gumana nang walang mga error.

Dito ko nais na agad na linawin na ang sinumang developer sa isang proyekto ay maaaring gumawa ng mga sangay, maaari rin siyang magpalit .gitlab-ci.yml file at i-access ang mga lihim na variable.
Samakatuwid, mahigpit na inirerekomenda na pahintulutan lamang ang kanilang paggamit para sa mga protektadong sanga, halimbawa sa panginoon, o lumikha ng isang hiwalay na hanay ng mga variable para sa bawat kapaligiran.

13. Suriin ang Apps

Suriin ang Apps Ito ay isang tampok na GitLab na nagbibigay-daan sa iyong magdagdag ng isang pindutan para sa bawat file sa repositoryo upang mabilis na makita ito sa isang naka-deploy na kapaligiran.

Upang lumitaw ang mga button na ito, kailangan mong lumikha ng isang file .gitlab/route-map.yml at ilarawan ang lahat ng mga pagbabago sa landas dito; sa aming kaso ito ay magiging napaka-simple:

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

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

Huwag kalimutang i-commit ang aming mga pagbabago:

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

git push, at suriin:

Screenshot ng button ng Review App

Sinusubukan ang mga bagong tool para sa pagbuo at pag-automate ng deployment sa Kubernetes

Tapos na ang trabaho!

Mga mapagkukunan ng proyekto:

Salamat sa iyong pansin, sana ay nagustuhan mo ito Sinusubukan ang mga bagong tool para sa pagbuo at pag-automate ng deployment sa Kubernetes

Pinagmulan: www.habr.com

Magdagdag ng komento