เช เชนเชเซเชเชค เชนเซเชตเชพ เชเชคเชพเช เชเซ เชฆเชฐเซเช เชตเซเชฏเชเซเชคเชฟ เชธเชพเชฐเซ เชฐเซเชคเซ เชเชพเชฃเซ เชเซ เชเซ เชคเชฎเชพเชฐเชพ เชธเซเชซเซเชเชตเซเชฐเชจเซเช เชชเชฐเซเชเซเชทเชฃ เชเชฐเชตเซเช เชฎเชนเชคเซเชตเชชเซเชฐเซเชฃ เช เชจเซ เชเชตเชถเซเชฏเช เชเซ, เช เชจเซ เชเชฃเชพ เชฒเชพเชเชฌเชพ เชธเชฎเชฏเชฅเซ เชคเซ เชเชชเชฎเซเชณเซ เชเชฐเซ เชฐเชนเซเชฏเชพ เชเซ, เชนเซเชฌเชฐเชจเซ เชตเชฟเชถเชพเชณเชคเชพเชฎเชพเช เชเชตเชพ เชฒเซเชเชชเซเชฐเชฟเชฏ เชเชคเซเชชเชพเชฆเชจเซเชจเชพ เชธเชเชฏเซเชเชจเชจเซ เชธเซเช เชเชฐเชตเชพ เชฎเชพเชเซ เชเช เชชเชฃ เชฐเซเชธเซเชชเซ เชจเชนเซเชคเซ. (เช เชฎเชพเชฐเชพ เชฎเชจเชชเชธเชเชฆ) GitLab เช เชจเซ JUnit เชคเชฐเซเชเซ เช เชตเชฟเชถเชฟเชทเซเช. เชเชพเชฒเซ เช เช เชเชคเชฐ เชญเชฐเซเช!
เชชเชฐเชฟเชเชฏ
เชชเซเชฐเชฅเชฎ, เชฎเชจเซ เชเซเชเชฒเชพเช เชธเชเชฆเชฐเซเชญ เชเชชเชตเชพ เชฆเซ:
- เช เชฎเชพเชฐเซ เชฌเชงเซ เชเชชเซเชฒเชฟเชเซเชถเชจเซ เชเซเชฌเชฐเชจเซเชเซเชธ เชชเชฐ เชเชพเชฒเชคเซ เชนเซเชตเชพเชฅเซ, เช เชฎเซ เชฏเซเชเซเชฏ เชเชจเซเชซเซเชฐเชพเชธเซเชเซเชฐเชเซเชเชฐ เชชเชฐ เชชเชฐเซเชเซเชทเชฃเซ เชเชฒเชพเชตเชตเชพเชจเซเช เชตเชฟเชเชพเชฐเซเชถเซเช.
- เชเชธเซเชฎเซเชฌเชฒเซ เช
เชจเซ เชเชฎเชพเชตเช เชฎเชพเชเซ เช
เชฎเซ เชเชชเชฏเซเช เชเชฐเซเช เชเซเช
เชตเชฐเซเชซ (เชเชจเซเชซเซเชฐเชพเชธเซเชเซเชฐเชเซเชเชฐ เชเชเชเซเชจเชพ เชธเชเชฆเชฐเซเชญเชฎเชพเช, เชเชจเซ เชเชชเชฎเซเชณเซ เช เชฐเซเชฅ เช เชชเชฃ เชฅเชพเชฏ เชเซ เชเซ เชนเซเชฒเซเชฎ เชธเชพเชฎเซเชฒ เชเซ). - เชนเซเช เชชเชฐเซเชเซเชทเชฃเซเชจเซ เชตเชพเชธเซเชคเชตเชฟเช เชฐเชเชจเชพเชจเซ เชตเชฟเชเชคเซเชฎเชพเช เชเชเชถ เชจเชนเซเช: เช เชฎเชพเชฐเชพ เชเชฟเชธเซเชธเชพเชฎเชพเช, เชเซเชฒเชพเชฏเชเช เชชเซเชคเซ เชชเชฐเซเชเซเชทเชฃเซ เชฒเชเซ เชเซ, เช เชจเซ เช เชฎเซ เชซเชเซเชค เชคเซเชฎเชจเชพ เชฒเซเชเชเชจเซ เชเชพเชคเชฐเซ เชเชฐเซเช เชเซเช (เช เชจเซ เชฎเชฐเซเช เชตเชฟเชจเชเชคเซเชฎเชพเช เช เชจเซเชฐเซเชช เช เชนเซเชตเชพเชฒเชจเซ เชนเชพเชเชฐเซ).
เชเซเชฐเชฟเชฏเชพเชเชจเซ เชธเชพเชฎเชพเชจเซเชฏ เชเซเชฐเชฎ เชเซเชตเซ เชฆเซเชเชพเชถเซ?
- เชเชชเซเชฒเชฟเชเซเชถเชจ เชฌเชจเชพเชตเชตเซ - เช เชฎเซ เช เชคเชฌเชเซเชเชพเชจเชพ เชตเชฐเซเชฃเชจเชจเซ เชเซเชกเซ เชฆเชเชถเซเช.
- เชเชชเซเชฒเชฟเชเซเชถเชจเชจเซ เชเซเชฌเชฐเชจเซเชเซเชธ เชเซเชฒเชธเซเชเชฐเชจเชพ เช เชฒเช เชจเซเชฎเชธเซเชชเซเชธ เชชเชฐ เชเชฎเชพเชตเซ เช เชจเซ เชชเชฐเซเชเซเชทเชฃ เชถเชฐเซ เชเชฐเซ.
- เชเชฐเซเชเชฟเชซเซเชเซเชเซเชธ เชฎเชพเชเซ เชถเซเชง เชเชฐเซ เชฐเชนเซเชฏเชพเช เชเซเช เช เชจเซ GitLab เชธเชพเชฅเซ JUnit เชฐเชฟเชชเซเชฐเซเชเซเชธเชจเซเช เชชเชฆเชเซเชเซเชฆเชจ เชเชฐเซ เชฐเชนเซเชฏเชพเช เชเซเช.
- เช เชเชพเช เชฌเชจเชพเชตเซเชฒ เชจเซเชฎเชธเซเชชเซเชธ เชเชพเชขเซ เชจเชพเชเชตเซเช.
เชนเชตเซ - เช เชฎเชฒเซเชเชฐเชฃ เชฎเชพเชเซ!
เชเซเช เชตเชฃ
เชเชฟเชเชฒเซเชฌ เชธเซ.เชเช.
เชเชพเชฒเซ เชเช เชเซเชเชกเซ เชธเชพเชฅเซ เชถเชฐเซ เชเชฐเซเช .gitlab-ci.yaml
, เชเซ เชเชชเซเชฒเชฟเชเซเชถเชจเชจเซ เชเชฎเชพเชตเชตเชพเชจเซเช เช
เชจเซ เชชเชฐเซเชเซเชทเชฃเซ เชเชฒเชพเชตเชตเชพเชจเซเช เชตเชฐเซเชฃเชจ เชเชฐเซ เชเซ. เชธเซเชเชฟ เชคเชฆเซเชฆเชจ เชชเซเชฐเชเชเชก เชนเซเชตเชพเชจเซเช เชฌเชนเชพเชฐ เชเชตเซเชฏเซเช เชเซ, เชคเซเชฅเซ เชคเซ เชเชฟเชชเซเชชเชฃเซเช เชธเชพเชฅเซ เชธเชเชชเซเชฐเซเชฃ เชฐเซเชคเซ เชชเซเชฐเช เชเซ:
variables:
# ะพะฑััะฒะปัะตะผ ะฒะตััะธั werf, ะบะพัะพััั ัะพะฑะธัะฐะตะผัั ะธัะฟะพะปัะทะพะฒะฐัั
WERF_VERSION: "1.0 beta"
.base_deploy: &base_deploy
script:
# ัะพะทะดะฐะตะผ namespace ะฒ K8s, ะตัะปะธ ะตะณะพ ะฝะตั
- kubectl --context="${WERF_KUBE_CONTEXT}" get ns ${CI_ENVIRONMENT_SLUG} || kubectl create ns ${CI_ENVIRONMENT_SLUG}
# ะทะฐะณััะถะฐะตะผ werf ะธ ะดะตะฟะปะพะธะผ โ ะฟะพะดัะพะฑะฝะตะต ะพะฑ ััะพะผ ัะผ. ะฒ ะดะพะบัะผะตะฝัะฐัะธะธ
# (https://werf.io/how_to/gitlab_ci_cd_integration.html#deploy-stage)
- type multiwerf && source <(multiwerf use ${WERF_VERSION})
- werf version
- type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
- werf deploy --stages-storage :local
--namespace ${CI_ENVIRONMENT_SLUG}
--set "global.commit_ref_slug=${CI_COMMIT_REF_SLUG:-''}"
# ะฟะตัะตะดะฐะตะผ ะฟะตัะตะผะตะฝะฝัั `run_tests`
# ะพะฝะฐ ะฑัะดะตั ะธัะฟะพะปัะทะพะฒะฐัััั ะฒ ัะตะฝะดะตัะต Helm-ัะตะปะธะทะฐ
--set "global.run_tests=${RUN_TESTS:-no}"
--set "global.env=${CI_ENVIRONMENT_SLUG}"
# ะธะทะผะตะฝัะตะผ timeout (ะฑัะฒะฐัั ะดะพะปะณะธะต ัะตััั) ะธ ะฟะตัะตะดะฐะตะผ ะตะณะพ ะฒ ัะตะปะธะท
--set "global.ci_timeout=${CI_TIMEOUT:-900}"
--timeout ${CI_TIMEOUT:-900}
dependencies:
- Build
.test-base: &test-base
extends: .base_deploy
before_script:
# ัะพะทะดะฐะตะผ ะดะธัะตะบัะพัะธั ะดะปั ะฑัะดััะตะณะพ ะพััะตัะฐ, ะธัั
ะพะดั ะธะท $CI_COMMIT_REF_SLUG
- mkdir /mnt/tests/${CI_COMMIT_REF_SLUG} || true
# ะฒัะฝัะถะดะตะฝะฝัะน ะบะพัััะปั, ั.ะบ. GitLab ั
ะพัะตั ะฟะพะปััะธัั ะฐััะตัะฐะบัั ะฒ ัะฒะพะตะผ build-dirโะต
- mkdir ./tests || true
- ln -s /mnt/tests/${CI_COMMIT_REF_SLUG} ./tests/${CI_COMMIT_REF_SLUG}
after_script:
# ะฟะพัะปะต ะพะบะพะฝัะฐะฝะธั ัะตััะพะฒ ัะดะฐะปัะตะผ ัะตะปะธะท ะฒะผะตััะต ั Jobโะพะผ
# (ะธ, ะฒะพะทะผะพะถะฝะพ, ะตะณะพ ะธะฝััะฐััััะบัััะพะน)
- type multiwerf && source <(multiwerf use ${WERF_VERSION})
- werf version
- type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
- werf dismiss --namespace ${CI_ENVIRONMENT_SLUG} --with-namespace
# ะผั ัะฐะทัะตัะฐะตะผ ะฟะฐะดะตะฝะธั, ะฝะพ ะฒั ะผะพะถะตัะต ัะดะตะปะฐัั ะธะฝะฐัะต
allow_failure: true
variables:
RUN_TESTS: 'yes'
# ะทะฐะดะฐะตะผ ะบะพะฝัะตะบัั ะฒ werf
# (https://werf.io/how_to/gitlab_ci_cd_integration.html#infrastructure)
WERF_KUBE_CONTEXT: 'admin@stage-cluster'
tags:
# ะธัะฟะพะปัะทัะตะผ ัะฐะฝะฝะตั ั ัะตะณะพะผ `werf-runner`
- werf-runner
artifacts:
# ััะตะฑัะตััั ัะพะฑัะฐัั ะฐััะตัะฐะบั ะดะปั ัะพะณะพ, ััะพะฑั ะตะณะพ ะผะพะถะฝะพ ะฑัะปะพ ัะฒะธะดะตัั
# ะฒ ะฟะฐะนะฟะปะฐะนะฝะต ะธ ัะบะฐัะฐัั โ ะฝะฐะฟัะธะผะตั, ะดะปั ะฑะพะปะตะต ะฒะดัะผัะธะฒะพะณะพ ะธะทััะตะฝะธั
paths:
- ./tests/${CI_COMMIT_REF_SLUG}/*
# ะฐััะตัะฐะบัั ััะฐััะต ะฝะตะดะตะปะธ ะฑัะดัั ัะดะฐะปะตะฝั
expire_in: 7 day
# ะฒะฐะถะฝะพ: ััะธ ัััะพะบะธ ะพัะฒะตัะฐัั ะทะฐ ะฟะฐััะธะฝะณ ะพััะตัะฐ GitLabโะพะผ
reports:
junit: ./tests/${CI_COMMIT_REF_SLUG}/report.xml
# ะดะปั ัะฟัะพัะตะฝะธั ะทะดะตัั ะฟะพะบะฐะทะฐะฝั ะฒัะตะณะพ ะดะฒะต ััะฐะดะธะธ
# ะฒ ัะตะฐะปัะฝะพััะธ ะถะต ั ะฒะฐั ะธั
ะฑัะดะตั ะฑะพะปััะต โ ะบะฐะบ ะผะธะฝะธะผัะผ ะธะท-ะทะฐ ะดะตะฟะปะพั
stages:
- build
- tests
build:
stage: build
script:
# ัะฑะพัะบะฐ โ ัะฝะพะฒะฐ ะฟะพ ะดะพะบัะผะตะฝัะฐัะธะธ ะฟะพ werf
# (https://werf.io/how_to/gitlab_ci_cd_integration.html#build-stage)
- type multiwerf && source <(multiwerf use ${WERF_VERSION})
- werf version
- type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
- werf build-and-publish --stages-storage :local
tags:
- werf-runner
except:
- schedules
run tests:
<<: *test-base
environment:
# "ัะฐะผะฐ ัะพะปั" ะธะผะตะฝะพะฒะฐะฝะธั namespaceโะฐ
# (https://docs.gitlab.com/ce/ci/variables/predefined_variables.html)
name: tests-${CI_COMMIT_REF_SLUG}
stage: tests
except:
- schedules
เชเซเชฏเซเชฌเชฐเซเชจเซเชเชฟเชธ
เชนเชตเซ เชกเชฟเชฐเซเชเซเชเชฐเซเชฎเชพเช .helm/templates
เชเชพเชฒเซ เชเซเชฌ เชธเชพเชฅเซ YAML เชฌเชจเชพเชตเซเช - tests-job.yaml
- เชชเชฐเซเชเซเชทเชฃเซ เชเชฒเชพเชตเชตเชพ เชฎเชพเชเซ เช
เชจเซ เชเซเชฌเชฐเชจเซเชเซเชธ เชธเชเชธเชพเชงเชจเซเชจเซ เชคเซเชจเซ เชเชฐเซเชฐ เชเซ. เชธเซเชเชฟ เชชเชเซ เชธเซเชชเชทเซเชเชคเชพ เชเซเช:
{{- if eq .Values.global.run_tests "yes" }}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: tests-script
data:
tests.sh: |
echo "======================"
echo "${APP_NAME} TESTS"
echo "======================"
cd /app
npm run test:ci
cp report.xml /app/test_results/${CI_COMMIT_REF_SLUG}/
echo ""
echo ""
echo ""
chown -R 999:999 /app/test_results/${CI_COMMIT_REF_SLUG}
---
apiVersion: batch/v1
kind: Job
metadata:
name: {{ .Chart.Name }}-test
annotations:
"helm.sh/hook": post-install,post-upgrade
"helm.sh/hook-weight": "2"
"werf/watch-logs": "true"
spec:
activeDeadlineSeconds: {{ .Values.global.ci_timeout }}
backoffLimit: 1
template:
metadata:
name: {{ .Chart.Name }}-test
spec:
containers:
- name: test
command: ['bash', '-c', '/app/tests.sh']
{{ tuple "application" . | include "werf_container_image" | indent 8 }}
env:
- name: env
value: {{ .Values.global.env }}
- name: CI_COMMIT_REF_SLUG
value: {{ .Values.global.commit_ref_slug }}
- name: APP_NAME
value: {{ .Chart.Name }}
{{ tuple "application" . | include "werf_container_env" | indent 8 }}
volumeMounts:
- mountPath: /app/test_results/
name: data
- mountPath: /app/tests.sh
name: tests-script
subPath: tests.sh
tolerations:
- key: dedicated
operator: Exists
- key: node-role.kubernetes.io/master
operator: Exists
restartPolicy: OnFailure
volumes:
- name: data
persistentVolumeClaim:
claimName: {{ .Chart.Name }}-pvc
- name: tests-script
configMap:
name: tests-script
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ .Chart.Name }}-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Mi
storageClassName: {{ .Chart.Name }}-{{ .Values.global.commit_ref_slug }}
volumeName: {{ .Values.global.commit_ref_slug }}
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: {{ .Values.global.commit_ref_slug }}
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 10Mi
local:
path: /mnt/tests/
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- kube-master
persistentVolumeReclaimPolicy: Delete
storageClassName: {{ .Chart.Name }}-{{ .Values.global.commit_ref_slug }}
{{- end }}
เชเซเชตเชพ เชชเซเชฐเชเชพเชฐเชจเชพ เชธเชเชธเชพเชงเชจเซ เช เชฐเซเชชเชฐเซเชเชพเชเชเชจเชฎเชพเช เชตเชฐเซเชฃเชตเซเชฒ เชเซ? เชเชฎเชพเชตเช เชเชฐเชคเซ เชตเชเชคเซ, เช
เชฎเซ เชชเซเชฐเซเชเซเชเซเช เชฎเชพเชเซ เชเช เช
เชจเชจเซเชฏ เชจเซเชฎเชธเซเชชเซเชธ เชฌเชจเชพเชตเซเช เชเซเช (เชเชฎเชพเช เชฆเชฐเซเชถเชพเชตเซเชฒ เชเซ .gitlab-ci.yaml
- tests-${CI_COMMIT_REF_SLUG}
) เช
เชจเซ เชคเซเชจเซ เชฐเซเชฒ เชเชเช เชเชฐเซ:
- ConfigMap เชเซเชธเซเช เชธเซเชเซเชฐเชฟเชชเซเช เชธเชพเชฅเซ;
- เชเซเชฌ เชชเซเชกเชจเชพ เชตเชฐเซเชฃเชจ เช
เชจเซ เชเชฒเซเชฒเซเชเชฟเชค เชจเชฟเชฐเซเชฆเซเชถ เชธเชพเชฅเซ
command
, เชเซ เชซเชเซเชค เชชเชฐเซเชเซเชทเชฃเซ เชเชฒเชพเชตเซ เชเซ; - เชชเซเชตเซ เช เชจเซ เชชเซเชตเซเชธเซ, เชเซ เชคเชฎเชจเซ เชเซเชธเซเช เชกเซเชเชพ เชธเซเชเซเชฐ เชเชฐเชตเชพเชจเซ เชฎเชเชเซเชฐเซ เชเชชเซ เชเซ.
เชธเชพเชฅเซ เชชเซเชฐเชพเชฐเชเชญเชฟเช เชธเซเชฅเชฟเชคเชฟ เชชเชฐ เชงเซเชฏเชพเชจ เชเชชเซ if
เชฎเซเชจเชฟเชซเซเชธเซเชเชจเซ เชถเชฐเซเชเชคเชฎเชพเช - เชคเชฆเชจเซเชธเชพเชฐ, เชเชชเซเชฒเชฟเชเซเชถเชจ เชธเชพเชฅเซ เชนเซเชฒเซเชฎ เชเชพเชฐเซเชเชจเซ เช
เชจเซเชฏ YAML เชซเชพเชเชฒเซ เชเชตเชฐเชฟเชค เชนเซเชตเซ เชเชตเชถเซเชฏเช เชเซ เชตเชฟเชชเชฐเซเชค เชกเชฟเชเชพเชเชจ เชเซเชฅเซ เชคเซเช เชชเชฐเซเชเซเชทเชฃ เชฆเชฐเชฎเชฟเชฏเชพเชจ เชคเซเชจเชพเชค เชจ เชฅเชพเชฏ. เชคเซ เช:
{{- if ne .Values.global.run_tests "yes" }}
---
ั ะดััะณะพะน ัะผะปะธะบ
{{- end }}
เชเซ เชเซ, เชเซ เชชเชฐเซเชเซเชทเชฃเซ เช เชฎเซเช เชเชจเซเชซเซเชฐเชพเชธเซเชเซเชฐเชเซเชเชฐเชจเซ เชเชฐเซเชฐ เชเซ (เชเชฆเชพเชนเชฐเชฃ เชคเชฐเซเชเซ, Redis, RabbitMQ, Mongo, PostgreSQL...) - เชคเซเชฎเชจเชพ YAML เชนเซเช เชถเชเซ เชเซ เชจเชฅเซ เชฌเชเชง เชเชฐเซ เชคเซเชฎเชจเซ เชชเชฐเซเชเซเชทเชฃ เชตเชพเชคเชพเชตเชฐเชฃเชฎเชพเช เชชเชฃ เชเซเช เชตเซ... เช เชฒเชฌเชคเซเชค, เชคเชฎเชจเซ เชฏเซเชเซเชฏ เชฒเชพเชเซ เชคเซเชฎ เชคเซเชฎเชจเซ เชธเชฎเชพเชฏเซเชเชฟเชค เชเชฐเซ.
เช เชเชคเชฟเชฎ เชธเซเชชเชฐเซเชถ
เชเชพเชฐเชฃ เชเซ เชเชธเซเชฎเซเชฌเชฒเซ เช
เชจเซ เชเชฎเชพเชตเช เชนเชฎเชฃเชพเช เชฎเชพเชเซ เชตเชฐเซเชซ เชตเชฐเซเชเซเชธเชจเซ เชเชชเชฏเซเช เชเชฐเซเชจเซ เชฎเชพเชคเซเชฐ เชฌเชฟเชฒเซเชก เชธเชฐเซเชตเชฐ เชชเชฐ (เชเซเชเชฒเซเชฌ-เชฐเชจเชฐ เชธเชพเชฅเซ), เช
เชจเซ เชชเชฐเซเชเซเชทเชฃเซ เชธเชพเชฅเซเชจเซ เชชเซเชก เชฎเชพเชธเซเชเชฐ เชชเชฐ เชฒเซเชเช เชเชฐเชตเชพเชฎเชพเช เชเชตเซ เชเซ, เชคเชฎเชพเชฐเซ เชกเชฟเชฐเซเชเซเชเชฐเซ เชฌเชจเชพเชตเชตเชพเชจเซ เชเชฐเซเชฐ เชชเชกเชถเซ /mnt/tests
เชฎเชพเชธเซเชเชฐ เชชเชฐ เช
เชจเซ เชคเซเชจเซ เชฐเชจเชฐเชจเซ เชเชชเซ, เชเชฆเชพเชนเชฐเชฃ เชคเชฐเซเชเซ, NFS เชฆเซเชตเชพเชฐเชพ. เชธเซเชชเชทเซเชเชคเชพ เชธเชพเชฅเซเชจเซเช เชตเชฟเชเชคเชตเชพเชฐ เชเชฆเชพเชนเชฐเชฃ เชเชฎเชพเช เชฎเชณเซ เชถเชเซ เชเซ
เชชเชฐเชฟเชฃเชพเชฎ เช เชนเชถเซ:
user@kube-master:~$ cat /etc/exports | grep tests
/mnt/tests IP_gitlab-builder/32(rw,nohide,insecure,no_subtree_check,sync,all_squash,anonuid=999,anongid=998)
user@gitlab-runner:~$ cat /etc/fstab | grep tests
IP_kube-master:/mnt/tests /mnt/tests nfs4 _netdev,auto 0 0
เชเชฟเชเชฒเซเชฌ-เชฐเชจเชฐ เชชเชฐ เชธเซเชงเชพ เช NFS เชถเซเชฐ เชฌเชจเชพเชตเชตเชพ เช เชจเซ เชชเชเซ เชคเซเชจเซ เชชเซเชกเซเชธเชฎเชพเช เชฎเชพเชเชจเซเช เชเชฐเชตเชพเชจเซ เชเซเช เชฎเชจเชพเช เชเชฐเชคเซเช เชจเชฅเซ.
เชจเซเชเชงเชฃเซ
เชคเชฎเซ เชเชฆเชพเช เชชเซเชเชคเชพ เชนเชถเซ เชเซ เชเซ เชคเชฎเซ เชธเซเชงเชพ เชถเซเชฒ เชฐเชจเชฐ เชชเชฐ เชชเชฐเซเชเซเชทเชฃเซ เชธเชพเชฅเซ เชธเซเชเซเชฐเชฟเชชเซเช เชเชฒเชพเชตเซ เชถเชเซ เชคเซ เชเซเชฌ เชฌเชจเชพเชตเซเชจเซ เชฌเชงเซเช เช เชเซเชฎ เชเชเชฟเชฒ เชฌเชจเชพเชตเชตเซเช? เชเชตเชพเชฌ เชธเชพเชต เชจเชเซเชตเซ เชเซ...
เชเซเชเชฒเชพเช เชชเชฐเซเชเซเชทเชฃเซ เชฏเซเชเซเชฏ เชฐเซเชคเซ เชเชพเชฐเซเชฏ เชเชฐเซ เชเซ เชคเซ เชเชเชพเชธเชตเชพ เชฎเชพเชเซ เชเชจเซเชซเซเชฐเชพเชธเซเชเซเชฐเชเซเชเชฐ (MongoDB, RabbitMQ, PostgreSQL, เชตเชเซเชฐเซ) เชธเซเชงเซ เชชเชนเซเชเชเชตเชพเชจเซ เชเชฐเซเชฐ เชเซ. เช เชฎเซ เชชเชฐเซเชเซเชทเชฃเชจเซ เชเชเซเชเซเชค เชเชฐเซเช เชเซเช - เช เช เชญเชฟเชเชฎ เชธเชพเชฅเซ, เชเชตเซ เชตเชงเชพเชฐเชพเชจเซ เชธเชเชธเซเชฅเชพเชเชจเซ เชธเชฎเชพเชตเซเชถ เชเชฐเชตเชพเชจเซเช เชธเชฐเชณ เชฌเชจเซ เชเซ. เช เชเชชเชฐเชพเชเชค, เช เชฎเชจเซ เชฎเชณเซ เชเซ เชฎเชพเชจเช เชเชฎเชพเชตเช เช เชญเชฟเชเชฎ (เชญเชฒเซ NFS เชจเซ เชเชชเชฏเซเช เชเชฐเซ, เชกเชฟเชฐเซเชเซเชเชฐเซเชเชจเซเช เชตเชงเชพเชฐเชพเชจเซเช เชฎเชพเชเชจเซเชเชฟเชเช).
เชชเชฐเชฟเชฃเชพเชฎ
เชเซเชฏเชพเชฐเซ เชเชชเชฃเซ เชคเซเชฏเชพเชฐ เชเชฐเซเชฒ เชฐเซเชชเชฐเซเชเชพเชเชเชจ เชฒเชพเชเซ เชเชฐเซเชถเซเช เชคเซเชฏเชพเชฐเซ เชเชชเชฃเซ เชถเซเช เชเซเชถเซเช?
เชฎเชฐเซเช เชตเชฟเชจเชเชคเซ เชคเซเชจเซ เชจเชตเซเชจเชคเชฎ เชชเชพเชเชชเชฒเชพเชเชจเชฎเชพเช เชเชพเชฒเชคเชพ เชชเชฐเซเชเซเชทเชฃเซ เชฎเชพเชเซ เชธเชพเชฐเชพเชเชถเชจเชพ เชเชเชเชกเชพ เชฌเชคเชพเชตเชถเซ:
เชฆเชฐเซเช เชญเซเชฒ เชตเชฟเชเชคเซ เชฎเชพเชเซ เช
เชนเซเช เชเซเชฒเชฟเช เชเชฐเซ เชถเชเชพเชฏ เชเซ:
NB: เชธเชเซเชค เชตเชพเชเช เชเซเชถเซ เชเซ เช
เชฎเซ เชจเซเชกเชเซเชเชธ เชเชชเซเชฒเชฟเชเซเชถเชจเชจเซเช เชชเชฐเซเชเซเชทเชฃ เชเชฐเซ เชฐเชนเซเชฏเชพ เชเซเช, เช
เชจเซ เชธเซเชเซเชฐเซเชจเชถเซเชเชฎเชพเช - .NET... เชเชถเซเชเชฐเซเชฏ เชชเชพเชฎเชถเซ เชจเชนเซเช: เชฒเซเชเชจเซ เชคเซเชฏเชพเชฐเซเชจเชพ เชญเชพเชเชฐเซเชชเซ, เชชเซเชฐเชฅเชฎ เชเชชเซเชฒเชฟเชเซเชถเชจเชจเชพ เชชเชฐเซเชเซเชทเชฃเชฎเชพเช เชเซเช เชญเซเชฒเซ เชฎเชณเซ เชจเชฅเซ, เชชเชฐเชเชคเซ เชคเซเช เชฌเซเชเชพเชฎเชพเช เชฎเชณเซ เชเชตเซเชฏเชพ เชนเชคเชพ.
เชจเชฟเชทเซเชเชฐเซเชท
เชเซเชฎ เชคเชฎเซ เชเซเช เชถเชเซ เชเซ, เชเชเช เชเชเชฟเชฒ เชจเชฅเซ!
เชธเซเชฆเซเชงเชพเชเชคเชฟเช เชฐเซเชคเซ, เชเซ เชคเชฎเชพเชฐเซ เชชเชพเชธเซ เชชเชนเซเชฒเซเชฅเซ เช เชถเซเชฒ เชเชฒเซเชเซเชเชฐ เชเซ เช
เชจเซ เชคเซ เชเชพเชฎ เชเชฐเซ เชเซ, เชชเชฐเชเชคเซ เชคเชฎเชพเชฐเซ เชเซเชฌเชฐเชจเซเชเซเชธเชจเซ เชเชฐเซเชฐ เชจเชฅเซ, เชคเซ เชคเซเชจเซ เชธเชพเชฅเซ เชชเชฐเซเชเซเชทเชฃ เชเซเชกเชตเซเช เช เช
เชนเซเช เชตเชฐเซเชฃเชตเซเชฒ เชเชฐเชคเชพเช เชตเชงเซ เชธเชฐเชณ เชเชพเชฐเซเชฏ เชนเชถเซ. เช
เชจเซ เชฎเชพเช
PS
เช เชฎเชพเชฐเชพ เชฌเซเชฒเซเช เชชเชฐ เชชเชฃ เชตเชพเชเชเซ:
- ยซ
เชเซเชฌเชฐเชจเซเชเซเชธ เช เชจเซ เชเชฟเชเชฒเซเชฌ เชธเชพเชฅเซ เชถเซเชฐเซเชทเซเช CI/CD เชชเซเชฐเซเชเซเชเชฟเชธ (เชธเชฎเซเชเซเชทเชพ เช เชจเซ เชตเชฟเชกเชฟเชฏเซ เชฐเชฟเชชเซเชฐเซเช) ยป; - ยซ
GitLab CI เชฎเชพเช เชเชธเซเชเชฎ เชตเชฐเซเชเชซเซเชฒเซ เชฌเชจเชพเชตเชตเชพ เชฎเชพเชเซเชจเซ เชเชฟเชชเซเชธ ยป; - ยซ
เชเชคเซเชชเชพเชฆเชจเชฎเชพเช เชธเชคเชค เชเชเซเชเชฐเชฃ เช เชจเซ เชกเชฟเชฒเชฟเชตเชฐเซ เชฎเชพเชเซ GitLab CI ยป.
เชธเซเชฐเซเชธ: www.habr.com