
تحية! في الآونة الأخيرة ، تم إطلاق العديد من أدوات التشغيل الآلي الرائعة لبناء صور Docker وللنشر على Kubernetes. في هذا الصدد ، قررت اللعب مع gitlab ، وكيفية دراسة قدراته ، وبطبيعة الحال ، تكوين خط الأنابيب.
كان مصدر إلهام هذا العمل هو موقع kubernetes.io ، الذي يتم إنشاؤه تلقائيًا من أكواد المصدر ، ولكل تجمع يتم إرساله ، يقوم الروبوت تلقائيًا بإنشاء نسخة معاينة للموقع مع تغييراتك ويوفر رابطًا للعرض.
حاولت إنشاء عملية مماثلة من الصفر ، لكنني اعتمدت بالكامل على Gitlab CI والأدوات المجانية التي اعتدت استخدامها لنشر التطبيقات في Kubernetes. اليوم سوف أخبركم أخيرًا عنهم.
سوف تنظر المقالة في أدوات مثل:
Hugo ، qbec ، kaniko ، git-crypt و GitLab CI مع إنشاء بيئات ديناميكية.
محتويات
- تقديم هوغو
- إعداد Dockerfile
- التعارف مع كانيكو
- تقديم qbec
- محاولة Gitlab- عداء مع Kubernetes- المنفذ
- نشر هيلم الخرائط مع qbec
- إدخال بوابة القبو
- إنشاء صورة مربع الأدوات
- لدينا أول خط أنابيب وتجميع الصور بالعلامات
- أتمتة النشر
- القطع الأثرية ودفع بناء في الماجستير
- البيئات الديناميكية
- مراجعة التطبيقات
1. تقديم هوغو
كمثال على مشروعنا ، سنحاول إنشاء موقع ويب لنشر الوثائق المبنية على Hugo. هوغو هو مولد محتوى ثابت.
بالنسبة لأولئك الذين ليسوا على دراية بمولدات الكهرباء الساكنة ، سوف أخبركم قليلاً عنهم. بخلاف محركات موقع قاعدة البيانات العادية وبعض محركات php التي ، عند المطالبة من قبل المستخدم ، تقوم بإنشاء صفحات أثناء الطيران ، يتم ترتيب المولدات الثابتة بشكل مختلف قليلاً. إنها تسمح لك بأخذ المصدر ، كقاعدة ، فهي عبارة عن مجموعة من الملفات في علامات التمييز والقوالب ، ثم تجميعها في موقع كامل التشطيب.
هذا هو ، في الإخراج ، ستحصل على بنية دليل ومجموعة من ملفات html التي تم إنشاؤها ، والتي يمكن تحميلها ببساطة إلى أي استضافة رخيصة والحصول على موقع عمل.
يمكن تثبيت هوغو محليًا وتجربته:
نهيئ الموقع الجديد:
hugo new site docs.example.org
وفي الوقت نفسه مستودع بوابة:
cd docs.example.org git init
حتى الآن ، يعد موقعنا أساسيًا ، ولكي يظهر عليه أولاً ، نحتاج إلى توصيل سمة أو سمة - إنها مجرد مجموعة من القوالب والقواعد المحددة مسبقًا والتي يتم من خلالها إنشاء موقعنا.
كموضوع ، سوف نستخدم Learn ، والتي ، في رأيي ، هي الأنسب لموقع مع الوثائق.
أود إيلاء اهتمام خاص لحقيقة أننا لسنا بحاجة إلى حفظ ملفات السمات في مستودع مشروعنا ، بدلاً من ذلك يمكننا ببساطة توصيله باستخدام git subodule :
git submodule add https://github.com/matcornic/hugo-theme-learn themes/learn
وبالتالي ، فإن الملفات المرتبطة مباشرة بمشروعنا فقط ستكون في مستودعنا ، وسيظل الموضوع المتصل في شكل رابط إلى مستودع محدد والالتزام به ، أي أنه يمكن دائمًا سحبه من المصدر الأصلي وعدم الخوف من التغييرات غير المتوافقة.
إصلاح 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 :-)
لقطة شاشة للصفحة التي تم إنشاؤها حديثًا لإنشاء موقع ، فقط قم بتشغيل:
hugo
محتويات العام / الدليل سيكون موقعك.
نعم ، بالمناسبة ، دعنا نضيفها على الفور إلى .gitignore :
echo /public > .gitignore
لا تنس أن تلتزم تغييراتنا:
git add . git commit -m "New site created"
2. إعداد Dockerfile
لقد حان الوقت لتحديد هيكل مستودعنا. عادةً ما أستخدم شيئًا مثل:
. ├── deploy │ ├── app1 │ └── app2 └── dockerfiles ├── image1 └── image2
- dockerfiles / - تحتوي على أدلة مع Dockerfiles وكل ما تحتاجه لبناء صور عامل ميناء لدينا.
- نشر / - يحتوي على أدلة لنشر تطبيقاتنا على Kubernetes
وبالتالي ، سنقوم بإنشاء أول Dockerfile لدينا على طول مسار 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" ]
كما ترون ، يحتوي Dockerfile على اثنين من FROMs ، تسمى هذه الميزة بناء متعدد المراحل ويسمح لك باستبعاد كل شيء غير ضروري من صورة عامل الإرساء النهائي.
وبالتالي ، سوف تحتوي الصورة النهائية على darkhttpd فقط (خادم HTTP خفيف الوزن) وعامة / - محتوى موقعنا الذي تم إنشاؤه بشكل ثابت.
لا تنس أن تلتزم تغييراتنا:
git add dockerfiles/website git commit -m "Add Dockerfile for website"
3. التعارف مع kaniko
كمجمّع من صور عامل الميناء ، قررت استخدام kaniko ، نظرًا لأنه لا يتطلب تشغيل برنامج تشغيل عامل الميناء ، ويمكن تنفيذ التجميع نفسه على أي جهاز وتخزين ذاكرة التخزين المؤقت مباشرةً في السجل ، مما يلغي الحاجة إلى تخزين كامل ثابت .
لإنشاء الصورة ، ما عليك سوى بدء تشغيل الحاوية باستخدام kaniko execate وتمرير سياق الإنشاء الحالي إليها ، ويمكنك القيام بذلك محليًا ، عبر عامل ميناء:
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 هو اسم صورة عامل الميناء الخاص بك ، وبعد التجميع سيتم دفعه تلقائيًا إلى سجل عامل الميناء.
تتيح لك المعلمة - cache تخزين طبقات في سجل عامل الميناء ، على سبيل المثال ، سيتم حفظها في registry.gitlab.com/kvaps/docs.example.org/website/cache ، ولكن يمكنك تحديد مسار آخر باستخدام --cache- المعلمة الريبو .
4. التعارف مع qbec
Qbec هي أداة نشر تتيح لك وصف بيان التطبيق الخاص بك ونشره على Kubernetes. يتيح لك استخدام Jsonnet باعتباره بناء الجملة الرئيسي تبسيط وصف الاختلافات إلى حد كبير في العديد من البيئات ، وأيضًا تقريبًا إزالة التكرار الكامل للكود.
يمكن أن يكون هذا صحيحًا بشكل خاص في الحالات التي تحتاج فيها إلى نشر تطبيق ما في عدة مجموعات ذات معلمات مختلفة وتريد وصفها بشكل تعريفي في Git.
يتيح لك Qbec أيضًا تقديم مخططات Helm عن طريق تمرير المعلمات اللازمة لها وتشغيلها لاحقًا بالإضافة إلى البيانات العادية ، بما في ذلك الطفرات المختلفة التي يمكن فرضها عليها ، وهذا بدوره يلغي الحاجة إلى استخدام ChartMuseum. هذا هو ، يمكنك تخزين وعرض المخططات مباشرة من بوابة ، حيث لديهم المكان.
كما قلت من قبل ، سنخزن جميع عمليات النشر في دليل النشر / :
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 ، وفي ملف params.libsonnet ، حيث يوضح المكان الذي تحتاج إلى أخذ المعلمات له.
التالي نرى دليلين:
- المكونات / - سيتم تخزين جميع البيانات الخاصة بتطبيقنا هنا ، ويمكن وصفها في ملفات 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 العادية ، من حيث المبدأ jsonnet صحيح بالفعل 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 عداء مع Kubernetes المنفذ
حتى وقت قريب ، كنت أستخدم فقط عداء gitlab المعتاد على جهاز مُجهز مسبقًا (حاوية LXC) مع قشرة أو منفّذة ميناء. في البداية ، كان لدينا العديد من هؤلاء المتسابقين الذين تم تعريفهم عالميًا في فريقنا. قاموا بجمع صور عامل ميناء لجميع المشاريع.
ولكن كما أظهرت الممارسة ، فإن هذا الخيار ليس هو الأكثر مثالية ، سواء من حيث التطبيق العملي أو من حيث الأمن. من الأفضل كثيرًا والأيديولوجيًا أن يتم نشر عدائين منفصلين لكل مشروع وحتى لكل بيئة.
لحسن الحظ ، هذه ليست مشكلة على الإطلاق ، حيث أننا سننشر الآن gitlab-runner مباشرة كجزء من مشروعنا مباشرة إلى Kubernetes.
يوفر Gitlab مخطط رأس جاهز لنشر عداء gitlab في 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 = true - يمنح العداء العدد المطلوب من الامتيازات ليكون قادرًا على إنشاء قرون لأداء مهامنا باستخدام المنفذ kubernetes.
إذا تم كل شيء بشكل صحيح ، يجب أن تشاهد العداء المسجل في قسم " العدائين" ، في إعدادات مشروعك.
هل هذا بسيط؟ - نعم بسيط جدا! لا مزيد من المتاعب مع تسجيل المتسابقين يدويا ، من الآن فصاعدا سيتم إنشاء المتسابقين وتدميرها تلقائيا.
6. نشر مخططات هيلم مع QBEC
نظرًا لأننا قررنا اعتبار gitlab-runner جزءًا من مشروعنا ، فقد حان الوقت لوصفه في مستودع Git الخاص بنا.
يمكننا وصفه على أنه مكون منفصل من موقع الويب ، ولكن في المستقبل نخطط لنشر نسخ مختلفة من الموقع في كثير من الأحيان ، على عكس gitlab-runner ، الذي سيتم نشره مرة واحدة فقط لكل مجموعة Kubernetes. لذلك دعونا تهيئة تطبيق منفصل لذلك:
cd deploy qbec init gitlab-runner cd gitlab-runner
هذه المرة لن نصف كيانات Kubernetes يدويًا ، لكن نأخذ مخطط هيلم الجاهز. واحدة من مزايا qbec هي القدرة على تقديم مخططات Helm مباشرة من مستودع Git.
دعونا توصيله باستخدام git subodule:
git submodule add https://gitlab.com/gitlab-org/charts/gitlab-runner vendor/gitlab-runner
الآن يحتوي دليل البائع / gitlab-runner على مستودعنا برسم بياني لـ 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, } )
الوسيطة الأولى لتوسيعHelmTemplate نقوم بتمرير المسار إلى المخطط ، ثم params.values ، التي نأخذها من معلمات البيئة ، ثم كائنًا به
- nameTemplate - اسم الإصدار
- مساحة الاسم - مساحة الاسم التي مرت على رأس
- thisFile - المعلمة المطلوبة تمرير المسار إلى الملف الحالي
- مطوّل - يعرض الأمر القالب helm مع كافة الوسائط عند تقديم المخطط
سنقوم الآن بوصف العوامل الخاصة بمكوننا في البيئات / base.libsonnet :
local secrets = import '../secrets/base.libsonnet'; { components: { gitlabRunner: { name: 'gitlab-runner', values: { gitlabUrl: 'https://gitlab.com/', rbac: { create: true, }, runnerRegistrationToken: secrets.runnerRegistrationToken, }, }, }, }
انتبه إلى runnerRegistrationToken التي نأخذها من ملف secrets / base.libsonnet الخارجي ، فلننشئه :
{ runnerRegistrationToken: 'yga8y-jdCusVDn_t4Wxc', }
تحقق مما إذا كان كل شيء يعمل:
qbec show default
إذا كان كل شيء على ما يرام ، فيمكننا إزالة الإصدار السابق من خلال إصدار Helm:
helm uninstall gitlab-runner
ونشرها ، ولكن بالفعل من خلال qbec:
qbec apply default
7. إدخال بوابة القبو
Git-crypt هي أداة تتيح لك إعداد تشفير شفاف لمستودع التخزين الخاص بك.
في الوقت الحالي ، يبدو هيكل دليلنا الخاص بعداء الجيتلاب كما يلي:
. ├── components │ ├── gitlab-runner.jsonnet ├── environments │ ├── base.libsonnet │ └── default.libsonnet ├── params.libsonnet ├── qbec.yaml ├── secrets │ └── base.libsonnet └── vendor └── gitlab-runner (submodule)
ولكن الحفاظ على الأسرار في بوابة ليست آمنة ، أليس كذلك؟ لذلك نحن بحاجة إلى تشفيرها بشكل صحيح.
عادةً من أجل متغير واحد ، هذا غير منطقي دائمًا. يمكنك تمرير الأسرار إلى qbec وعبر متغيرات البيئة لنظام CI الخاص بك.
لكن تجدر الإشارة إلى أن هناك المزيد من المشاريع المعقدة التي يمكن أن تحتوي على أسرار أكثر بكثير ؛ سيكون من الصعب للغاية نقلها جميعًا من خلال متغيرات البيئة.
بالإضافة إلى ذلك ، في هذه الحالة ، لن أتمكن من إخبارك عن هذه الأداة الرائعة مثل git-crypt .
يعد git-crypt مناسبًا أيضًا لأنه يتيح لك حفظ تاريخ الأسرار بالكامل ، وكذلك مقارنة التعارضات ودمجها وحلها بنفس الطريقة التي اعتدنا القيام بها في حالة Git.
أولاً وقبل كل شيء ، بعد تثبيت git-crypt ، نحتاج إلى إنشاء مفاتيح لمستودعنا:
git crypt init
إذا كان لديك مفتاح PGP ، فيمكنك إضافة نفسك فورًا كمتعاون لهذا المشروع:
git-crypt add-gpg-user kvapss@gmail.com
وبالتالي ، يمكنك دائمًا فك تشفير هذا المستودع باستخدام المفتاح الخاص.
إذا لم يكن لديك مفتاح PGP ولم يكن متوقعًا ، فيمكنك الذهاب في الاتجاه الآخر وتصدير مفتاح المشروع:
git crypt export-key /path/to/keyfile
وبهذه الطريقة ، سيتمكن أي شخص لديه ملف مفتاح تصدير من فك تشفير مستودعك.
لقد حان الوقت لإعداد أول سر لدينا.
اسمحوا لي أن أذكرك بأننا ما زلنا في دليل نشر / gitlab-runner / ، حيث لدينا أسرار / دليل ، فلنشفّر جميع الملفات الموجودة فيه ، ولهذا نقوم بإنشاء ملف أسرار / .gitattributes بالمحتويات التالية:
* filter=git-crypt diff=git-crypt .gitattributes !filter !diff
كما ترون من المحتوى ، سيتم تشغيل جميع الملفات عن طريق قناع * من خلال git-crypt ، باستثناء .gitattributes نفسها
يمكننا التحقق من ذلك عن طريق تشغيل:
git crypt status -e
في المخرجات ، نحصل على قائمة بجميع الملفات في المستودع الذي تم تمكين التشفير
هذا كل شيء ، الآن يمكننا الالتزام بأمان بتغيراتنا:
cd ../.. git add . git commit -m "Add deploy for gitlab-runner"
لحظر المستودع ، قم فقط بما يلي:
git crypt lock
ثم تتحول جميع الملفات المشفرة إلى شيء ثنائي ، سيكون من المستحيل قراءتها.
لفك تشفير مستودع التخزين ، قم بما يلي:
git crypt unlock
صورة مربع الأدوات عبارة عن صورة بها جميع الأدوات التي سنستخدمها لنشر مشروعنا. سيتم استخدامه من قبل عداء 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.
للقيام بذلك ، انتقل إلى الدليل باستخدام gitlab-runner:
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
كما لا تنسى أن تلتزم تغييراتنا في بوابة:
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. نظرًا لأنه يمكن أيضًا تعيين علامات جديدة على عمليات ارتكاب قديمة ، في هذه الحالة ، سيؤدي تهيئة خط الأنابيب لها إلى نشر الإصدار القديم.
لحل هذه المشكلة ، عادةً ما يتم إرفاق تجميع صور عامل الإرساء بالعلامات ، ونشر التطبيق على الفرع الرئيسي ، حيث تكون إصدارات الصور التي تم تجميعها مضغوطة. في هذه الحالة ، يمكنك تهيئة التراجع باستخدام علامة الرجوع الرئيسية البسيطة.
10. نشر التشغيل الآلي
لكي يقوم Gitlab-runner بفك تشفير أسرارنا ، نحتاج إلى تصدير مفتاح المستودع ، وإضافته إلى متغيرات بيئة CI الخاصة بنا:
git crypt export-key /tmp/docs-repo.key base64 -w0 /tmp/docs-repo.key; echo
احفظ السلسلة الناتجة في Gitlab ، لهذا سننتقل إلى إعدادات مشروعنا:
الإعدادات -> CI / CD -> المتغيرات
:
.gitlab-ci.yml :
.deploy_qbec_app: stage: deploy only: refs: - master deploy_gitlab_runner: extends: .deploy_qbec_app variables: GIT_SUBMODULE_STRATEGY: normal before_script: - base64 -d "$GITCRYPT_KEY" | git-crypt unlock - script: - qbec apply default --root deploy/gitlab-runner --force:k8s-context __incluster__ --wait --yes deploy_website: extends: .deploy_qbec_app script: - qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yes
qbec:
- --root some/app —
- --force:k8s-context __incluster__ — , gtilab-runner. , qbec Kubernetes- kubeconfig
- --wait — qbec , Ready exit-code.
- --yes — Are you sure? .
:
git add .gitlab-ci.yml git commit -m "Automate deploy"
git push :
11. push master
, . digest master-.
: website push master , Kubernetes.
.gitlab-ci.yml :
build_website: extends: .build_docker_image variables: GIT_SUBMODULE_STRATEGY: normal script: - mkdir -p $CI_PROJECT_DIR/artifacts - /kaniko/executor --cache --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/dockerfiles/website/Dockerfile --destination $CI_REGISTRY_IMAGE/website:$CI_COMMIT_REF_NAME --digest-file $CI_PROJECT_DIR/artifacts/website.digest artifacts: paths: - artifacts/ only: refs: - master - tags deploy_website: extends: .deploy_qbec_app script: - DIGEST="$(cat artifacts/website.digest)" - qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST"
, master refs build_website $CI_COMMIT_REF_NAME $CI_COMMIT_TAG , Git . , , docker-registry.
docker- , Kubernetes, , .
--vm:ext-str digest="$DIGEST" qbec — jsonnet. . , , , .
Kaniko digest ( --digest-file )
.
deploy/website/environments/base.libsonnet :
{ components: { website: { name: 'example-docs', image: 'registry.gitlab.com/kvaps/docs.example.org/website@' + std.extVar('digest'), replicas: 1, containerPort: 80, servicePort: 80, nodeSelector: {}, tolerations: [], ingressClass: 'nginx', domain: 'docs.example.org', }, }, }
, master docker- website , Kubernetes.
:
git add . git commit -m "Configure dynamic build"
, git push - :
gitlab-runner push, , , , .gitlab-ci.yml :
deploy_gitlab_runner: extends: .deploy_qbec_app variables: GIT_SUBMODULE_STRATEGY: normal before_script: - base64 -d "$GITCRYPT_KEY" | git-crypt unlock - script: - qbec apply default --root deploy/gitlab-runner --force:k8s-context __incluster__ --wait --yes only: changes: - deploy/gitlab-runner/**/*
changes deploy/gitlab-runner/
:
git add .gitlab-ci.yml git commit -m "Reduce gitlab-runner deploy"
git push , - :
12. Dynamic environments
.
build_website .gitlab-ci.yml , only , Gitlab :
build_website: extends: .build_docker_image variables: GIT_SUBMODULE_STRATEGY: normal script: - mkdir -p $CI_PROJECT_DIR/artifacts - /kaniko/executor --cache --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/dockerfiles/website/Dockerfile --destination $CI_REGISTRY_IMAGE/website:$CI_COMMIT_REF_NAME --digest-file $CI_PROJECT_DIR/artifacts/website.digest artifacts: paths: - artifacts/
deploy_website , environment :
deploy_website: extends: .deploy_qbec_app environment: name: prod url: https://docs.example.org script: - DIGEST="$(cat artifacts/website.digest)" - qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST"
Gitlab prod .
:
deploy_website: extends: .deploy_qbec_app environment: name: prod url: https://docs.example.org script: - DIGEST="$(cat artifacts/website.digest)" - qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST" deploy_review: extends: .deploy_qbec_app environment: name: review/$CI_COMMIT_REF_NAME url: http://$CI_ENVIRONMENT_SLUG.docs.example.org on_stop: stop_review script: - DIGEST="$(cat artifacts/website.digest)" - qbec apply review --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST" --vm:ext-str subdomain="$CI_ENVIRONMENT_SLUG" --app-tag "$CI_ENVIRONMENT_SLUG" only: refs: - branches except: refs: - master stop_review: extends: .deploy_qbec_app environment: name: review/$CI_COMMIT_REF_NAME action: stop stage: deploy before_script: - git clone "$CI_REPOSITORY_URL" master - cd master script: - qbec delete review --root deploy/website --force:k8s-context __incluster__ --yes --vm:ext-str digest="$DIGEST" --vm:ext-str subdomain="$CI_ENVIRONMENT_SLUG" --app-tag "$CI_ENVIRONMENT_SLUG" variables: GIT_STRATEGY: none only: refs: - branches except: refs: - master when: manual
push master preview .
qbec: --app-tag — , Kubernetes qbec .
review, .
qbec apply review , qbec apply default — (review default):
review deploy/website/qbec.yaml
spec: environments: review: defaultNamespace: docs server: https://kubernetes.example.org:8443
deploy/website/params.libsonnet :
local env = std.extVar('qbec.io/env'); local paramsMap = { _: import './environments/base.libsonnet', default: import './environments/default.libsonnet', review: import './environments/review.libsonnet', }; if std.objectHas(paramsMap, env) then paramsMap[env] else error 'environment ' + env + ' not defined in ' + std.thisFile
deploy/website/environments/review.libsonnet :
stop_review , gitlab checkout GIT_STRATEGY: none , master - review .
, .
review , .
:
git add . git commit -m "Enable automatic review"
git push , git checkout -b test , git push origin test , :
? — , : git checkout master , git push origin :test , environment .
, , .gitlab-ci.yml .
protected-, master , .
13. Review Apps
Review Apps , .
, .gitlab/route-map.yml , :
# Indices - source: /content\/(.+?)_index\.(md|html)/ public: '\1' # Pages - source: /content\/(.+?)\.(md|html)/ public: '\1/'
:
git add .gitlab/ git commit -m "Enable review apps"
git push , :
Job is done!
:
, 