تجربة أدوات جديدة لإنشاء النشر وأتمتة في Kubernetes

تجربة أدوات جديدة لإنشاء النشر وأتمتة في Kubernetes

مرحبًا! تم إصدار الكثير من أدوات الأتمتة الرائعة مؤخرًا لكل من إنشاء صور Docker ونشرها على Kubernetes. في هذا الصدد ، قررت أن ألعب مع Gitlab ، وكيفية دراسة قدراتها ، وبالطبع إنشاء خط أنابيب.

هذا الموقع مستوحى من kubernetes.io، والذي تم إنشاؤه من أكواد المصدر تلقائيًا ، ولكل طلب سحب يتم إرساله ، يقوم الروبوت تلقائيًا بإنشاء إصدار معاينة للموقع مع تغييراتك ويوفر ارتباطًا للعرض.

حاولت إنشاء عملية مماثلة من البداية ، لكنها مبنية بالكامل على Gitlab CI والأدوات المجانية التي استخدمتها لنشر التطبيقات على Kubernetes. اليوم سوف أخبرك أخيرًا المزيد عنها.

ستغطي المقالة أدوات مثل:
هوغو, كيوبيك, كانيكو, بوابة القبو и جيت لاب CI مع خلق بيئات ديناميكية.

محتويات

  1. التعرف على هوغو
  2. تحضير ملف Dockerfile
  3. التعرف على كانيكو
  4. مقدمة إلى qbec
  5. تجربة Gitlab-runner مع Kubernetes-المنفذ
  6. انشر مخططات Helm مع qbec
  7. مقدمة إلى git-crypt
  8. قم بإنشاء صورة مربع الأدوات
  9. أول خط أنابيب لدينا وتجميع الصور بالعلامات
  10. نشر الأتمتة
  11. القطع الأثرية والتجميع عند الدفع لإتقان
  12. البيئات الديناميكية
  13. مراجعة التطبيقات

1. التعرف على هوغو

كمثال على مشروعنا ، سنحاول إنشاء موقع لنشر الوثائق مبني على Hugo. هوغو هو منشئ محتوى ثابت.

بالنسبة لأولئك الذين ليسوا على دراية بالمولدات الثابتة ، سأخبركم المزيد عنها. على عكس محركات الموقع العادية التي تحتوي على قاعدة بيانات ونوع من أنواع ملفات php ، والتي ، عندما يطلبها المستخدم ، تنشئ صفحات أثناء التنقل ، يتم ترتيب المولدات الثابتة بشكل مختلف قليلاً. إنها تسمح لك بأخذ الكود المصدري ، عادةً مجموعة من الملفات في Markdown وقوالب السمات ، ثم تجميعها في موقع مكتمل بالكامل.

أي أنه عند الإخراج ستحصل على بنية دليل ومجموعة من ملفات html التي تم إنشاؤها والتي يمكنك ببساطة تحميلها إلى أي استضافة رخيصة والحصول على موقع عمل.

يمكنك تثبيت Hugo محليًا وتجربته:

تهيئة الموقع الجديد:

hugo new site docs.example.org

وفي نفس الوقت مستودع git:

cd docs.example.org
git init

حتى الآن ، موقعنا أصلي ولكي يظهر شيء ما عليه ، نحتاج أولاً إلى ربط سمة ، الموضوع هو مجرد مجموعة من القوالب والقواعد المحددة التي يتم من خلالها إنشاء موقعنا.

كموضوع سوف نستخدمه تعلّمِ، وهو ، في رأيي ، الأنسب لموقع يحتوي على وثائق.

أود أن أولي اهتمامًا خاصًا لحقيقة أننا لسنا بحاجة إلى حفظ ملفات السمات في مستودع مشروعنا ، بدلاً من ذلك يمكننا ببساطة توصيلها باستخدام نموذج بوابة:

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

وبالتالي ، سيحتوي مستودعنا فقط على ملفات مرتبطة مباشرة بمشروعنا ، وسيظل السمة المتصلة كرابط لمستودع معين والتزام فيه ، أي أنه يمكن دائمًا سحبها من المصدر الأصلي وعدم الخوف من تغييرات غير متوافقة.

دعونا نصلح ملف config config.toml:

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

بالفعل في هذه المرحلة ، يمكنك تشغيل:

hugo server

وعلى العنوان http://localhost:1313/ تحقق من موقعنا الذي تم إنشاؤه حديثًا ، كل التغييرات التي تم إجراؤها في الدليل تقوم تلقائيًا بتحديث الصفحة المفتوحة في المتصفح ، وهي مريحة للغاية!

دعنا نحاول إنشاء صفحة عنوان بتنسيق المحتوى / _index.md:

# My docs site

## Welcome to the docs!

You will be very smart :-)

لقطة شاشة للصفحة المنشأة حديثًا

تجربة أدوات جديدة لإنشاء النشر وأتمتة في Kubernetes

لإنشاء موقع ، ما عليك سوى تشغيل:

hugo

محتوى الدليل عامة/ وسيكون موقعك.
نعم ، بالمناسبة ، دعنا ندخله على الفور .gitignore:

echo /public > .gitignore

لا تنسَ إجراء تغييراتنا:

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

2. تحضير Dockerfile

حان الوقت لتحديد هيكل مستودعنا. عادةً ما أستخدم شيئًا مثل:

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

  • ملفات رصيف / - تحتوي على أدلة مع Dockerfiles وكل ما يلزم لبناء صور عامل الإرساء لدينا.
  • نشر/ - يحتوي على أدلة لنشر تطبيقاتنا في Kubernetes

وبالتالي ، سننشئ أول ملف Dockerfile على طول الطريق dockerfiles / موقع الويب / 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" ]

كما ترى ، يحتوي Dockerfile على اثنين من عند، هذا الاحتمال يسمى بناء متعدد المراحل ويسمح لك باستبعاد كل شيء غير ضروري من صورة عامل الإرساء النهائية.
وبالتالي ، فإن الصورة النهائية ستحتوي فقط داركتشتبد (خادم HTTP خفيف الوزن) و عامة/ - محتوى موقعنا الذي تم إنشاؤه بشكل ثابت.

لا تنسَ إجراء تغييراتنا:

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

3. التعرف على كانيكو

باعتباري منشئ صور عامل الإرساء ، قررت استخدام كانيكو، نظرًا لأنه لا يتطلب تشغيل برنامج Docker daemon ، ويمكن تنفيذ التجميع نفسه على أي جهاز وتخزين ذاكرة التخزين المؤقت مباشرة في السجل ، وبالتالي التخلص من الحاجة إلى وجود مساحة تخزين ثابتة كاملة.

لإنشاء الصورة ، ما عليك سوى تشغيل الحاوية باستخدام منفذ كانيكو وتمرير سياق البناء الحالي إليه ، يمكنك القيام بذلك محليًا ، عبر عامل الإرساء:

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 - اسم صورة عامل الإرساء ، بعد إنشائها سيتم تشغيلها تلقائيًا في سجل عامل الإرساء.

المعلمة --مخبأ يسمح لك بتخزين الطبقات مؤقتًا في سجل عامل الميناء ، على سبيل المثال المعين ، سيتم تخزينها فيه Registry.gitlab.com/kvaps/docs.example.org/website/cache، ولكن يمكنك تحديد مسار آخر باستخدام المعلمة - ذاكرة التخزين المؤقت.

لقطة شاشة لسجل عامل ميناء

تجربة أدوات جديدة لإنشاء النشر وأتمتة في Kubernetes

4. مقدمة في qbec

كيوبيك هي أداة نشر تتيح لك وصف بيانات التطبيق بشكل إعلاني ونشرها على Kubernetes. إن استخدام Jsonnet باعتباره البنية الأساسية يجعل من السهل جدًا وصف الاختلافات في بيئات متعددة ، كما أنه يقضي تمامًا تقريبًا على تكرار الكود.

يمكن أن يكون هذا صحيحًا بشكل خاص في الحالات التي تحتاج فيها إلى نشر تطبيق في مجموعات متعددة بمعلمات مختلفة وتريد وصفها بشكل إعلاني في Git.

يسمح لك Qbec أيضًا بتقديم مخططات Helm من خلال تمرير المعلمات الضرورية ثم العمل عليها بنفس طريقة البيانات العادية ، بما في ذلك القدرة على تطبيق طفرات مختلفة عليها ، وهذا بدوره يلغي الحاجة إلى استخدام ChartMuseum. بمعنى أنه يمكنك تخزين الرسوم البيانية وعرضها مباشرة من git حيث تنتمي.

كما قلت من قبل ، سنخزن جميع عمليات النشر في الدليل نشر/:

mkdir deploy
cd deploy

دعنا نبدأ تطبيقنا الأول:

qbec init website
cd website

الآن يبدو هيكل تطبيقنا كما يلي:

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

انظر إلى الملف qbec.yaml:

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

هنا نحن مهتمون في المقام الأول المواصفات البيئات، لقد أنشأت qbec بالفعل البيئة الافتراضية لنا وأخذت عنوان الخادم ومساحة الاسم من kubeconfig الحالي.
الآن عند النشر إلى الافتراضي البيئة ، سيتم نشر qbec دائمًا فقط في مجموعة Kubernetes المحددة ومساحة الاسم المحددة ، أي لم تعد مضطرًا للتبديل بين السياقات ومساحات الأسماء من أجل النشر.
إذا لزم الأمر ، يمكنك دائمًا تحديث الإعدادات في هذا الملف.

جميع بيئاتك موصوفة في qbec.yamlو في الملف البارامز، والذي يوضح المكان الذي يجب أن تأخذ فيه المعلمات.

بعد ذلك نرى دليلين:

  • المكونات / - سيتم تخزين جميع بيانات تطبيقنا هنا ، ويمكن وصفها في كل من jsonnet وملفات yaml العادية
  • البيئات / - هنا سنصف جميع المتغيرات (المعلمات) لبيئاتنا.

بشكل افتراضي لدينا ملفان:

  • البيئات / base.libsonnet - سيحتوي على معلمات مشتركة لجميع البيئات
  • البيئات / default.libsonnet - يحتوي على معلمات أعيد تحديدها للبيئة الافتراضي

دعونا فتح البيئات / base.libsonnet وأضف معلمات لمكوننا الأول هناك:

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

لنقم أيضًا بإنشاء المكون الأول المكونات / 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,
                },
              },
            ],
          },
        },
      ],
    },
  },
]

في هذا الملف ، وصفنا ثلاثة كيانات Kubernetes في وقت واحد ، وهي: قابل للفتح, العطاء и دخول. إذا رغبت في ذلك ، يمكننا نقلها إلى مكونات مختلفة ، ولكن في هذه المرحلة ، واحد كافٍ بالنسبة لنا.

بناء الجملة jsonnet تشبه إلى حد كبير json العادية ، من حيث المبدأ ، json العادية هي بالفعل jsonnet صالحة ، لذلك قد يكون من الأسهل عليك في البداية استخدام خدمات عبر الإنترنت مثل yaml2json لتحويل yaml المعتاد إلى json ، أو إذا كانت مكوناتك لا تحتوي على أي متغيرات ، فيمكن وصفها في شكل yaml العادي.

عند العمل مع jsonnet أنصحك بشدة بتثبيت مكون إضافي للمحرر الخاص بك

على سبيل المثال ، هناك مكون إضافي لـ vim vim-jsonnet، والذي يقوم بتشغيل تمييز بناء الجملة والتنفيذ تلقائيًا jsonnet FMT على كل حفظ (يتطلب تثبيت jsonnet).

كل شيء جاهز ، الآن يمكننا بدء النشر:

لنرى ما حصلنا عليه ، دعنا نجري:

qbec show default

في الإخراج ، سترى بيانات yaml المعروضة التي سيتم تطبيقها على المجموعة الافتراضية.

حسنًا ، قدم الآن:

qbec apply default

سيُظهر لك الإخراج دائمًا ما سيتم عمله على مجموعتك ، وسيطلب منك qbec قبول التغييرات عن طريق الكتابة y يمكنك تأكيد نواياك.

تم الآن نشر تطبيقنا!

إذا تم إجراء تغييرات ، فيمكنك دائمًا تشغيل:

qbec diff default

لمعرفة كيف ستؤثر هذه التغييرات على النشر الحالي

لا تنسَ إجراء تغييراتنا:

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

5. جرب Gitlab-runner مع Kubernetes-المنفذ

حتى وقت قريب ، كنت أستخدم العادية فقط عداء جيت لاب على آلة معدة مسبقًا (حاوية LXC) مع غلاف أو منفذ رصيف. في البداية ، كان لدينا العديد من هؤلاء العدائين المحددين عالميًا في gitlab الخاص بنا. قاموا ببناء صور عامل ميناء لجميع المشاريع.

ولكن كما أظهرت الممارسة ، فإن هذا الخيار ليس هو الخيار الأمثل ، سواء من حيث التطبيق العملي أو من حيث الأمن. من الأفضل والصحيح أيديولوجيًا أن يتم نشر متسابقين منفصلين لكل مشروع ، وحتى لكل بيئة.

لحسن الحظ ، هذه ليست مشكلة على الإطلاق ، لأننا سننتشر الآن عداء جيت لاب مباشرة كجزء من مشروعنا في Kubernetes.

يوفر Gitlab مخطط قيادة جاهز لنشر gitlab-runner على Kubernetes. لذلك كل ما تحتاج إلى معرفته هو رمز التسجيل لمشروعنا في الإعدادات -> CI / CD -> العدائين وتمريرها للقيادة:

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

حيث:

  • https://gitlab.com هو عنوان خادم Gitlab الخاص بك.
  • yga8y-jdCusVDn_t4Wxc - رمز التسجيل لمشروعك.
  • rbac.create = صحيح - يمنح العداء العدد اللازم من الامتيازات ليتمكن من إنشاء كبسولات لأداء مهامنا باستخدام kubernetes-المنفذ.

إذا تم كل شيء بشكل صحيح ، يجب أن ترى العداء المسجل في القسم وفاز بالمركز الثاني، في إعدادات مشروعك.

لقطة من العداء المضاف

تجربة أدوات جديدة لإنشاء النشر وأتمتة في Kubernetes

هل هذا بسيط؟ - نعم ، الأمر بهذه البساطة! لا مزيد من المتاعب مع تسجيل المتسابقين يدويًا ، من الآن فصاعدًا سيتم إنشاء المتسابقين وتدميرهم تلقائيًا.

6. انشر مخططات Helm مع QBEC

منذ أن قررنا النظر عداء جيت لاب جزء من مشروعنا ، حان الوقت لوصفه في مستودع Git الخاص بنا.

يمكننا وصفه بأنه مكون منفصل موقع الكتروني، لكننا نخطط لنشر نسخ مختلفة في المستقبل موقع الكتروني في كثير من الأحيان ، على عكس عداء جيت لاب، والتي سيتم نشرها مرة واحدة فقط لكل مجموعة Kubernetes. لذلك دعونا نقوم بتهيئة تطبيق منفصل لذلك:

cd deploy
qbec init gitlab-runner
cd gitlab-runner

هذه المرة لن نصف كيانات Kubernetes يدويًا ، لكننا سنأخذ مخطط Helm جاهزًا. تتمثل إحدى مزايا qbec في القدرة على عرض مخططات Helm مباشرة من مستودع Git.

لنقم بتمكينه باستخدام الوحدة الفرعية git:

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

الآن الدليل البائع / عداء gitlab يحتوي على مستودعنا مع رسم بياني لـ gitlab-runner.

يمكن ربط المستودعات الأخرى بطريقة مماثلة ، على سبيل المثال ، المستودع بأكمله مع الرسوم البيانية الرسمية https://github.com/helm/charts

دعنا نصف المكون المكونات / 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,
  }
)

الحجة الأولى ل توسيع نمرر المسار إلى الرسم البياني ، إذن المعلمات، التي نأخذها من معلمات البيئة ، ثم نأتي إلى الكائن

  • الاسم - اسم الإصدار
  • مساحة الاسم - تم تمرير مساحة الاسم للقيادة
  • هذا الملف - معلمة مطلوبة تمرر المسار إلى الملف الحالي
  • مطنب - يظهر الأمر قالب الدفة مع كل الحجج عند تقديم مخطط

الآن دعنا نصف معلمات المكون الخاص بنا في البيئات / base.libsonnet:

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

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

لاحظ عداء التسجيل نجلب من ملف خارجي الأسرار / base.libsonnet، فلنقم بإنشائه:

{
  runnerRegistrationToken: 'yga8y-jdCusVDn_t4Wxc',
}

دعنا نتحقق مما إذا كان كل شيء يعمل:

qbec show default

إذا كان كل شيء على ما يرام ، فيمكننا إزالة نشرنا سابقًا عبر إصدار Helm:

helm uninstall gitlab-runner

ونشره ولكن من خلال qbec:

qbec apply default

7. مقدمة في git-crypt

بوابة القبو هي أداة تسمح لك بإعداد تشفير شفاف لمستودعك.

في الوقت الحالي ، تبدو بنية الدليل الخاصة بنا لـ gitlab-runner كما يلي:

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

لكن تخزين الأسرار في Git ليس آمنًا ، أليس كذلك؟ لذلك نحن بحاجة إلى تشفيرها بشكل صحيح.

عادة لا يكون ذلك منطقيًا من أجل متغير واحد. يمكنك نقل الأسرار إلى كيوبيك ومن خلال متغيرات البيئة لنظام CI الخاص بك.
ولكن تجدر الإشارة إلى أن هناك أيضًا مشاريع أكثر تعقيدًا يمكن أن تحتوي على المزيد من الأسرار ، وسيكون من الصعب للغاية تمريرها جميعًا من خلال متغيرات البيئة.

بالإضافة إلى ذلك ، في هذه الحالة ، لن أتمكن من إخبارك عن أداة رائعة مثل بوابة القبو.

بوابة القبو كما أنها مريحة من حيث أنها تسمح لك بحفظ تاريخ الأسرار بالكامل ، بالإضافة إلى المقارنة والدمج وحل النزاعات بالطريقة نفسها التي اعتدنا عليها في حالة Git.

أول شيء بعد التثبيت بوابة القبو نحتاج إلى إنشاء مفاتيح لمستودعنا:

git crypt init

إذا كان لديك مفتاح PGP ، فيمكنك على الفور إضافة نفسك كمتعاون في هذا المشروع:

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

بهذه الطريقة يمكنك دائمًا فك تشفير هذا المستودع باستخدام مفتاحك الخاص.

إذا لم يكن لديك مفتاح PGP ولا يُتوقع منك ذلك ، فيمكنك حينئذٍ الذهاب في الاتجاه الآخر وتصدير مفتاح المشروع:

git crypt export-key /path/to/keyfile

وبالتالي ، فإن أي شخص يمتلك ملف ملف مفتاح سيكون قادرًا على فك تشفير المستودع الخاص بك.

حان الوقت لإعداد سرنا الأول.
دعني أذكرك أننا ما زلنا في الدليل نشر / gitlab-runner /حيث لدينا دليل أسرار /، فلنعمر جميع الملفات الموجودة فيه ، لذلك سننشئ ملفًا الأسرار / .gitattributes بمحتوى مثل هذا:

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

كما يتضح من المحتوى ، كل الملفات عن طريق القناع * سوف تمر من خلال بوابة القبو، باستثناء .gitattributes

يمكننا التحقق من ذلك من خلال تشغيل:

git crypt status -e

عند الإخراج ، نحصل على قائمة بجميع الملفات الموجودة في المستودع التي تم تمكين التشفير لها

هذا كل شيء ، يمكننا الآن تنفيذ تغييراتنا بأمان:

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

من أجل حظر المستودع ، يكفي تنفيذ:

git crypt lock

وعلى الفور ستتحول جميع الملفات المشفرة إلى شيء ثنائي ، وسيكون من المستحيل قراءتها.
لفك تشفير المستودع ، قم بتشغيل:

git crypt unlock

8. إنشاء صورة مربع الأدوات

صورة صندوق الأدوات هي صورة تحتوي على جميع الأدوات التي سنستخدمها لنشر مشروعنا. سيتم استخدامه بواسطة عداء gitlab لأداء مهام النشر النموذجية.

كل شيء بسيط هنا ، نصنع ملفًا جديدًا dockerfiles / toolbox / Dockerfile بمحتوى مثل هذا:

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

كما ترى ، في هذه الصورة نقوم بتثبيت جميع الأدوات المساعدة التي استخدمناها لنشر تطبيقنا. لا نحتاج هنا إلا إذا kubectl، ولكن قد ترغب في التلاعب بها عند إعداد خط الأنابيب.

أيضًا ، حتى نتمكن من التواصل مع Kubernetes ونشره ، نحتاج إلى إعداد دور للبودات التي تم إنشاؤها بواسطة gitlab-runner.

للقيام بذلك ، انتقل إلى الدليل باستخدام gitlab-runner'om:

cd deploy/gitlab-runner

وإضافة مكون جديد المكونات / 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,
      },
    ],
  },
]

نصف المعلمات الجديدة في البيئات / base.libsonnet، الذي يبدو الآن كالتالي:

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

لاحظ $ .components.rbac.name يعود الى الاسم للمكون RBAC

دعنا نتحقق مما تغير:

qbec diff default

ونطبق تغييراتنا على Kubernetes:

qbec apply default

أيضًا ، لا تنسَ إجراء تغييراتنا على 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. أول خط أنابيب لدينا وتجميع الصور بالعلامات

في جذر المشروع سنقوم بإنشائه .gitlab-ci.yml بمحتوى مثل هذا:

.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

يرجى ملاحظة أننا نستخدم GIT_SUBMODULE_STRATEGY: عادي لتلك الوظائف حيث تحتاج إلى تهيئة الوحدات الفرعية بشكل صريح قبل التنفيذ.

لا تنسَ إجراء تغييراتنا:

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

أعتقد أنه يمكنك تسميتها نسخة بأمان v0.0.1 وأضف علامة:

git tag v0.0.1

سنعلق العلامات كلما احتجنا إلى إصدار إصدار جديد. سيتم تعيين العلامات في صور Docker إلى علامات Git. ستعمل كل دفعة بعلامة جديدة على تهيئة بناء صورة بهذه العلامة.

دعنا نقوم به git push - العلامات، وإلقاء نظرة على خط الأنابيب الأول لدينا:

لقطة من خط الأنابيب الأول

تجربة أدوات جديدة لإنشاء النشر وأتمتة في Kubernetes

تجدر الإشارة إلى أن الإنشاءات القائمة على العلامات جيدة لبناء صور عامل الإرساء ، ولكن ليس لنشر تطبيق على Kubernetes. نظرًا لأنه يمكن أيضًا تعيين العلامات الجديدة للالتزامات القديمة ، في هذه الحالة ، ستؤدي تهيئة خط الأنابيب لها إلى نشر الإصدار القديم.

لحل هذه المشكلة ، عادة ما يتم ربط بناء صور عامل الإرساء بالعلامات ، ونشر التطبيق على الفرع رئيسي، حيث يتم ترميز إصدارات الصور المجمعة. في هذه الحالة يمكنك تهيئة التراجع عن طريق إرجاع بسيط رئيسي- الفروع.

10. نشر الأتمتة

لكي يتمكن Gitlab-runner من فك تشفير أسرارنا ، نحتاج إلى تصدير مفتاح المستودع وإضافته إلى متغيرات بيئة CI الخاصة بنا:

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

سنحفظ السلسلة الناتجة في Gitlab ، لذلك سننتقل إلى إعدادات مشروعنا:
الإعدادات -> CI / CD -> المتغيرات

وأنشئ متغيرًا جديدًا:

النوع
القفل
القيم
محمي
مقنع
مجال

File
GITCRYPT_KEY
<your string>
true (في وقت التدريب ، يمكنك ذلك false)
true
All environments

لقطة شاشة للمتغير المضاف

تجربة أدوات جديدة لإنشاء النشر وأتمتة في Kubernetes

لنقم الآن بتحديث ملف .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:

  • - جذر بعض / التطبيق - يسمح لك بتحديد دليل تطبيق معين
  • --فرض: k8s- سياق __incluster__ - هذا متغير سحري يقول أن النشر سيحدث في نفس المجموعة التي يعمل بها gtilab-runner. هذا ضروري ، وإلا ستحاول qbec العثور على خادم Kubernetes مناسب في kubeconfig الخاص بك
  • -انتظر - يفرض على شركة qbec الانتظار حتى تدخل الموارد التي تنشئها في حالة الاستعداد وعندها فقط تكتمل برمز خروج ناجح.
  • -نعم - فقط يعطل الغلاف التفاعلي هل أنت واثق؟ أثناء النشر.

لا تنسَ إجراء تغييراتنا:

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

و بعد دفعة غيت سنرى كيف تم نشر تطبيقاتنا:

لقطة من خط الأنابيب الثاني

تجربة أدوات جديدة لإنشاء النشر وأتمتة في Kubernetes

11. القطع الأثرية والتجميع عند الضغط على إتقان

عادةً ما تكون الخطوات المذكورة أعلاه كافية لإنشاء أي خدمة مصغرة وتقديمها تقريبًا ، لكننا لا نريد إضافة علامة في كل مرة نحتاج فيها إلى تحديث الموقع. لذلك ، سنذهب بطريقة أكثر ديناميكية ونقوم بإعداد نشر ملخص في الفرع الرئيسي.

الفكرة بسيطة: الآن صورة موقع الكتروني ستتم إعادة بنائه في كل مرة تضغط فيها رئيسي، ثم النشر تلقائيًا إلى 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"

يرجى ملاحظة أننا قمنا بإضافة فرع رئيسي к الحكام للوظيفة بناء_الموقع ونحن نستخدمها الآن CI_COMMIT_REF_NAME دولار بدلا من CI_COMMIT_TAG دولار، أي أننا نتخلص من العلامات في Git والآن سنقوم بدفع الصورة باسم فرع الالتزام الذي قام بتهيئة خط الأنابيب الخاص بك. تجدر الإشارة إلى أن هذا سيعمل أيضًا مع العلامات ، والتي ستسمح لنا بحفظ لقطات من الموقع بإصدار محدد في سجل عامل الميناء.

عندما لا يتغير اسم علامة docker للإصدار الجديد من الموقع ، فلا يزال يتعين علينا وصف التغييرات لـ Kubernetes ، وإلا فلن يقوم ببساطة بإعادة نشر التطبيق من الصورة الجديدة ، لأنه لن يلاحظ أي تغييرات في بيان النشر.

خيار --vm: ext-str Digest = "$ DIGEST" لـ qbec - يسمح لك بتمرير متغير خارجي إلى jsonnet. نريد إعادة نشر تطبيقنا في المجموعة مع كل إصدار. لم يعد بإمكاننا استخدام اسم العلامة ، الذي لا يمكن تغييره الآن ، لأننا نحتاج إلى الارتباط بإصدار معين من الصورة وتشغيل النشر عندما يتغير.

هنا ، ستساعدنا قدرة Kaniko على حفظ ملخص الصورة في ملف (الخيار - ديجيست ملف)
ثم نقوم بنقل هذا الملف وقراءته وقت النشر.

لنقم بتحديث معلمات نشر / موقع ويب / بيئات / 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',
    },
  },
}

تم ، الآن أي التزام في رئيسي يهيئ بناء صورة عامل الإرساء لـ موقع الكتروني، ثم نشره في Kubernetes.

لا تنسَ إجراء تغييراتنا:

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

تحقق من ذلك بعد دفعة غيت يجب أن نرى شيئًا كهذا:

لقطة شاشة لخط الأنابيب للسيد

تجربة أدوات جديدة لإنشاء النشر وأتمتة في Kubernetes

من حيث المبدأ ، لا نحتاج إلى إعادة نشر gitlab-runner مع كل دفعة ، ما لم يتغير شيء بالطبع في تكوينه ، فلنصلح هذا في .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/**/*

التغييرات سيتعقب التغييرات في نشر / gitlab-runner / ولن نطلق عملنا إلا إذا كان هناك أي شيء

لا تنسَ إجراء تغييراتنا:

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

دفعة غيت، هذا أفضل:

لقطة شاشة لخط الأنابيب المحدث

تجربة أدوات جديدة لإنشاء النشر وأتمتة في Kubernetes

12. البيئات الديناميكية

حان الوقت لتنويع خطوط الأنابيب لدينا مع البيئات الديناميكية.

أولاً ، دعنا نحدث الوظيفة بناء_الموقع في منطقتنا .gitlab-ci.yml، إزالة الكتلة منه فقط، مما سيجبر 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:
  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 بربط الوظيفة بـ همز البيئة وعرض الرابط الصحيح لها.

الآن دعنا نضيف وظيفتين أخريين:

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

سيتم تشغيلها عن طريق الدفع إلى أي فرع باستثناء الرئيسي وسيتم نشر إصدار معاينة للموقع.

نرى خيارًا جديدًا لـ qbec: - علامة التطبيق - يسمح لك بتمييز الإصدارات المنشورة من التطبيق والعمل فقط ضمن هذه العلامة ؛ عند إنشاء الموارد وتدميرها في Kubernetes ، سيعمل qbec عليها فقط.
وبالتالي ، لا يمكننا إنشاء بيئة منفصلة لكل مراجعة ، ولكن ببساطة نعيد استخدام نفس البيئة.

هنا نستخدم أيضًا ملفات qbec تطبيق مراجعة، بدلاً من qbec تطبيق الافتراضي - هذه هي اللحظة التي سنحاول فيها وصف الاختلافات في بيئاتنا (مراجعة وافتراضي):

دعنا نضيف مراجعة البيئة فيها نشر / موقع / qbec.yaml

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

ثم نعلن ذلك في نشر / موقع / 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

واكتب معلمات مخصصة لها بتنسيق نشر / موقع / بيئات / 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 الخروج منه GIT_STRATEGY: لا شيء، في وقت لاحق نحن استنساخ رئيسي-فرع وحذف المراجعة من خلاله.
محيرة بعض الشيء ، لكني لم أجد طريقة أجمل بعد.
قد يكون الخيار البديل هو نشر كل مراجعة في مساحة اسم فندق ، والتي يمكن دائمًا هدمها بالكامل.

لا تنسَ إجراء تغييراتنا:

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

دفعة غيت, اختبار git checkout -b, اختبار أصل دفع بوابة، يفحص:

لقطة شاشة للبيئات التي تم إنشاؤها في Gitlab

تجربة أدوات جديدة لإنشاء النشر وأتمتة في Kubernetes

كل شيء يعمل؟ - رائع ، احذف فرع الاختبار الخاص بنا: بوابة الخروج, أصل دفع بوابة: الاختبار، نتحقق من أن وظائف حذف البيئة تعمل دون أخطاء.

هنا أريد أن أوضح على الفور أن أي مطور في المشروع يمكنه إنشاء فروع ، يمكنه أيضًا التغيير .gitlab-ci.yml ملف والوصول إلى المتغيرات السرية.
لذلك ، يوصى بشدة بالسماح باستخدامها فقط للفروع المحمية ، على سبيل المثال في رئيسي، أو أنشئ مجموعة منفصلة من المتغيرات لكل بيئة.

13 مراجعة التطبيقات

مراجعة التطبيقات هذه ميزة gitlab تتيح لك إضافة زر لكل ملف في المستودع لعرضه بسرعة في البيئة المنشورة.

لكي تظهر هذه الأزرار ، تحتاج إلى إنشاء ملف .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"

دفعة غيت، و تأكد:

لقطة شاشة لزر مراجعة التطبيق

تجربة أدوات جديدة لإنشاء النشر وأتمتة في Kubernetes

ويتم العمل!

مصادر المشروع:

شكرا لك على اهتمامك ، أتمنى أن تنال إعجابك تجربة أدوات جديدة لإنشاء النشر وأتمتة في Kubernetes

المصدر: www.habr.com

إضافة تعليق