{"id":340714,"date":"2022-11-03T09:00:55","date_gmt":"2022-11-03T09:00:55","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=340714"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=340714","title":{"rendered":"<span>Canary-\u0440\u0435\u043b\u0438\u0437\u044b \u0432 Kubernetes \u043d\u0430 \u0431\u0430\u0437\u0435 Ingress-NGINX Controller<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0422\u0435\u043c\u0430 \u00ab\u043a\u0430\u043d\u0430\u0440\u0435\u0435\u0447\u043d\u044b\u0445\u00bb (canary) \u0440\u0435\u043b\u0438\u0437\u043e\u0432 \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u043b\u0430\u0441\u044c \u0432 \u043d\u0430\u0448\u0435\u043c \u0431\u043b\u043e\u0433\u0435 \u0443\u0436\u0435 \u043d\u0435 \u0440\u0430\u0437 \u2014 \u0441\u043c. \u0441\u0441\u044b\u043b\u043a\u0438 \u0432 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438. \u041d\u043e \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043b\u0438\u0448\u043d\u0438\u043c \u043d\u0430\u043f\u043e\u043c\u043d\u0438\u0442\u044c, \u0437\u0430\u0447\u0435\u043c \u043e\u043d\u0438 \u043d\u0443\u0436\u043d\u044b.<\/p>\n<p>Canary-\u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u0433\u0440\u0443\u043f\u043f\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439. \u0413\u0440\u0443\u043f\u043f\u0430 \u0432\u044b\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u043c\u0443 \u043f\u0440\u0438\u0437\u043d\u0430\u043a\u0443. \u0422\u0435\u0441\u0442 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0437\u0430\u0442\u0440\u0430\u0433\u0438\u0432\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0435\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439. \u041d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043c\u0435\u0436\u0434\u0443 \u0434\u0432\u0443\u043c\u044f \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c\u0441\u044f \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u043e.\u00a0<\/p>\n<p>Canary-\u0440\u0435\u043b\u0438\u0437\u044b \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0442\u0441\u044f \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 Ingress-\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0442\u0430\u043a\u0438\u0445 \u0440\u0435\u043b\u0438\u0437\u043e\u0432 \u0432 Kubernetes \u043d\u0430 \u0431\u0430\u0437\u0435 <a href=\"https:\/\/github.com\/kubernetes\/ingress-nginx\"><u>Ingress NGINX Controller<\/u><\/a>.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f9e\/a12\/fcb\/f9ea12fcbd9837a644dde29aac8fd4b9.png\" width=\"1878\" height=\"1080\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f9e\/a12\/fcb\/f9ea12fcbd9837a644dde29aac8fd4b9.png\"\/><figcaption><\/figcaption><\/figure>\n<blockquote>\n<p><strong>\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435<\/strong><\/p>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043a \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043e\u0431\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u0438\u043c\u0435\u043d\u043d\u043e \u0447\u0435\u0440\u0435\u0437 Ingress. \u0415\u0441\u043b\u0438 \u0432\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442 \u0441 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435\u043c \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 Service, \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u043d\u0435 \u043f\u043e\u0434\u043e\u0439\u0434\u0435\u0442.<\/p>\n<\/blockquote>\n<h2>\u0413\u043e\u0442\u043e\u0432\u0438\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432<\/h2>\n<p>\u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u0412\u043e\u0437\u044c\u043c\u0435\u043c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 NGINX, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0434\u0430\u0432\u0430\u0442\u044c \u043e\u0434\u043d\u0443 HTML-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443, \u0438 Ingress-\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440, \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u043c \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0443.<\/p>\n<p>\u041f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f \u0442\u0430\u043a\u043e\u0439 \u0447\u0430\u0440\u0442:<\/p>\n<pre><code class=\"yaml\">apiVersion: apps\/v1 kind: Deployment metadata:   name: {{ .Chart.Name }} spec:   revisionHistoryLimit: 3   selector:     matchLabels:       app: {{ .Chart.Name }}   replicas: 1   template:     metadata:       annotations:         checksum\/config: {{ include (print $.Template.BasePath \"\/10-nginx-config.yaml\") . | sha256sum }}       labels:         app: {{ .Chart.Name }}     spec:       volumes:       - name: configs         configMap:           name: {{ .Chart.Name }}-configmap       containers:       - name: nginx         imagePullPolicy: Always         image: {{ index .Values.werf.image \"nginx\" }}         lifecycle:           preStop:             exec:               command: [ \"\/bin\/bash\", \"-c\", \"sleep 5; kill -QUIT 1\" ]         command: [\"\/usr\/sbin\/nginx\", \"-g\", \"daemon off;\"]         ports:         - containerPort: 80           name: http           protocol: TCP         volumeMounts:         - name: configs           mountPath: \/etc\/nginx\/nginx.conf           subPath: nginx.conf         resources:           requests:             cpu: 50m             memory: 128Mi           limits:             memory: 128Mi --- apiVersion: v1 kind: Service metadata:   name: {{ .Chart.Name }} spec:   clusterIP: None   selector:     app: {{ .Chart.Name }}   ports:   - name: http     port: 80  --- apiVersion: v1 kind: ConfigMap metadata:   name: {{ .Chart.Name }}-configmap data:   nginx.conf: |     error_log  \/dev\/stderr;     events {       worker_connections 100000;       multi_accept on;     }     http {         charset utf-8;          server {             listen 80;             index index.html;             root \/app;             error_log \/dev\/stderr;             location \/ {                 try_files $uri \/index.html$is_args$args;             }         }     }  --- apiVersion: networking.k8s.io\/v1 kind: Ingress metadata:   name: {{ .Chart.Name }} spec:   rules:   - host: \"canary-example.flant.com\"     http:       paths:       - path: \"\/\"         pathType: Prefix         backend:           service:             name: {{ .Chart.Name }}             port:               number: 80<\/code><\/pre>\n<p>\u0412 \u043a\u043e\u0440\u0435\u043d\u044c \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0434\u0430\u0432\u0430\u0442\u044c \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440. \u041d\u0430\u0437\u043e\u0432\u0435\u043c \u0435\u0435 <code>index.html<\/code>:<\/p>\n<pre><code class=\"xml\">&lt;!DOCTYPE html> &lt;html> &lt;body> Hi! I'm another one typical nginx! &lt;\/body> &lt;\/html><\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0434\u043b\u044f \u0434\u0435\u043f\u043b\u043e\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f CI*.<\/p>\n<details class=\"spoiler\">\n<summary>* \u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0412 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d \u0434\u0435\u043f\u043b\u043e\u0439 \u043d\u0430 \u0431\u0430\u0437\u0435 GitLab CI + <a href=\"https:\/\/ru.werf.io\/\"><u>werf<\/u><\/a>.<\/p>\n<\/div>\n<\/details>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 werf \u2014 <code>werf.yaml<\/code>:<\/p>\n<pre><code class=\"yaml\">project: canary-example configVersion: 1 deploy:  helmRelease: '[[ project ]]\"'  namespace: \"[[ project ]]\"  --- image: nginx from: nginx:stable git: - add: \/   to: \/app   excludePaths:   - .helm   - werf.yaml   - .getlab-ci.yml<\/code><\/pre>\n<p>\u2026 \u0438 \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 GitLab CI \u2014 <code>.gitlab-ci.yml<\/code> **:<\/p>\n<pre><code class=\"yaml\">stages:   - converge  .base_converge: &amp;base_converge   stage: converge   script:     - werf converge    except:     - schedules   tags:     - werf  Converge base:   &lt;&lt;: *base_converge   environment:     name: canary-example   when: manual<\/code><\/pre>\n<details class=\"spoiler\">\n<summary>** \u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435<\/summary>\n<div class=\"spoiler__content\">\n<p>\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043f\u0440\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 werf \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u043e\u0431\u0440\u0430\u0437\u043e\u0432 \u0438 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/ru.werf.io\/documentation\/v1.2\/quickstart.html\"><u>\u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438<\/u><\/a>. \u0412\u0441\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0435 \u043a\u043e\u0434\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0447\u0430\u0440\u0442\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 <a href=\"https:\/\/github.com\/flant\/examples\/tree\/master\/2022\/10-canary-example\"><u>\u0432 \u043d\u0430\u0448\u0435\u043c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/u><\/a>.<\/p>\n<\/div>\n<\/details>\n<p>\u0420\u0430\u0437\u0432\u0435\u0440\u043d\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0435, \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0432 CI, \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c, \u0447\u0442\u043e \u043e\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442:<\/p>\n<pre><code class=\"bash\">$ curl canary-example.flant.com  Hi! I'm another one typical nginx!<\/code><\/pre>\n<p>\u041e\u0442\u043b\u0438\u0447\u043d\u043e!\u00a0<\/p>\n<p>\u041f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 canary-\u0440\u0435\u043b\u0438\u0437\u043e\u0432.<\/p>\n<h2>\u0414\u0435\u043b\u0430\u0435\u043c \u00ab\u043a\u0430\u043d\u0430\u0440\u0435\u0435\u0447\u043d\u044b\u0439\u00bb \u0440\u0435\u043b\u0438\u0437<\/h2>\n<p>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043c \u0434\u0432\u0435 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f \u0434\u0432\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 Helm-\u0440\u0435\u043b\u0438\u0437\u0430.\u00a0<\/p>\n<p>\u041c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u0440\u0430\u043d\u0435\u0435 CI, \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u0432 \u043d\u0435\u0433\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 Job \u0434\u043b\u044f canary-\u0434\u0435\u043f\u043b\u043e\u044f \u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <code>$CANARY_DEPLOY<\/code>, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0432 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 Helm-\u0440\u0435\u043b\u0438\u0437\u0430.\u00a0<\/p>\n<p>\u0412\u043d\u0435\u0441\u0435\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0444\u0430\u0439\u043b\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u2014 \u0432 <code>.gitlab-ci.yml<\/code>:<\/p>\n<pre><code class=\"yaml\">stages:   - converge  .base_converge: &amp;base_converge   stage: converge   script:     - export CI_HELM_RELEASE=${CANARY_DEPLOY}     - werf converge        --set \"global.canary_deploy=${CANARY_DEPLOY:-}\"   except:     - schedules   tags:     - werf  Converge base:   &lt;&lt;: *base_converge   environment:     name: canary-example   when: manual   variables:     CANARY_DEPLOY: \"\"  Converge canary::   &lt;&lt;: *base_converge   environment:     name: canary-example   when: manual   variables:     CANARY_DEPLOY: \"-canary\"<\/code><\/pre>\n<p>\u2026 \u0438 \u0432 <code>werf.yaml<\/code>:<\/p>\n<pre><code class=\"yaml\">project: canary-example configVersion: 1 deploy:  helmRelease: '[[ project ]]{{ env \"CI_HELM_RELEASE\" }}'  namespace: \"[[ project ]]\"  --- image: nginx from: nginx:stable git: - add: \/   to: \/app   excludePaths:   - .helm   - werf.yaml   - .getlab-ci.yml<\/code><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u0432 <code>.gitlab-ci.yml<\/code> \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f <code>$CANARY_DEPLOY<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043e\u0431\u043e\u0438\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430\u0445 \u0434\u0435\u043f\u043b\u043e\u044f (<code>base<\/code> \u0438 <code>canary<\/code>). \u041d\u043e \u0432 \u043f\u0435\u0440\u0432\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u043d\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043b\u0438\u0448\u044c \u043f\u0443\u0441\u0442\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443, \u0430 \u043f\u0440\u0438 canary \u2014 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>-canary<\/code>. \u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0440\u0435\u043b\u0438\u0437 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f <code>nginx-example<\/code>, \u0430 canary-\u0440\u0435\u043b\u0438\u0437 \u2014 <code>nginx-example-canary<\/code>.<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u043d\u0430 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0432 \u0440\u0435\u043b\u0438\u0437\u0430\u0445 \u043d\u0435 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u043b\u0438, \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u043c \u0447\u0430\u0440\u0442. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043f\u043e \u0448\u0430\u0431\u043b\u043e\u043d\u0443 \u00ab\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0447\u0430\u0440\u0442\u0430 + \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 <code>global.canary_deploy<\/code>\u00bb:<\/p>\n<pre><code class=\"yaml\">{{ $name := printf \"%s%s\" (.Chart.Name) (.Values.global.canary_deploy) }} apiVersion: apps\/v1 kind: Deployment metadata:   name: {{ $name }} spec:   revisionHistoryLimit: 3   selector:     matchLabels:       app: {{ $name }}   replicas: 1   template:     metadata:       annotations:         checksum\/config: {{ include (print $.Template.BasePath \"\/10-nginx-config.yaml\") . | sha256sum }}       labels:         app: {{ $name }}     spec:       imagePullSecrets:       - name: registrysecret       volumes:       - name: configs         configMap:           name: {{ $name }}-configmap       containers:       - name: nginx         imagePullPolicy: Always         image: {{ index .Values.werf.image \"nginx\" }}         lifecycle:           preStop:             exec:               command: [ \"\/bin\/bash\", \"-c\", \"sleep 5; kill -QUIT 1\" ]         command: [\"\/usr\/sbin\/nginx\", \"-g\", \"daemon off;\"]         ports:         - containerPort: 80           name: http           protocol: TCP         volumeMounts:         - name: configs           mountPath: \/etc\/nginx\/nginx.conf           subPath: nginx.conf         resources:           requests:             cpu: 50m             memory: 128Mi           limits:             memory: 128Mi --- apiVersion: v1 kind: Service metadata:   name:{{ $name }} spec:   clusterIP: None   selector:     app: {{ $name }}   ports:   - name: http     port: 80  --- apiVersion: v1 kind: ConfigMap metadata:   name: {{ $name }}-configmap data:   nginx.conf: |     error_log  \/dev\/stderr;     events {       worker_connections 100000;       multi_accept on;     }     http {         charset utf-8;          server {             listen 80;             index index.html;             root \/app;             error_log \/dev\/stderr;             location \/ {                 try_files $uri \/index.html$is_args$args;             }         }     }<\/code><\/pre>\n<p>\u0412 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u0430 Ingress \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442, \u043a\u0430\u043a\u043e\u0439 \u043f\u0440\u043e\u0446\u0435\u043d\u0442 \u0442\u0440\u0430\u0444\u0438\u043a\u0430 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043d\u0430\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0432 canary-\u0432\u0435\u0440\u0441\u0438\u044e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"yaml\">{{ $name := printf \"%s%s\" (.Chart.Name) (.Values.global.canary_deploy) }} apiVersion: networking.k8s.io\/v1 kind: Ingress metadata:   name: {{ $name }} {{- if ne .Values.global.canary_deploy \"\" }}   annotations:    nginx.ingress.kubernetes.io\/canary: \"true\"    nginx.ingress.kubernetes.io\/canary-weight: \"30\" {{- end }} spec:   rules:   - host: \"canary-example.flant.com\"     http:       paths:       - path: \"\/\"         pathType: Prefix         backend:           service:             name: {{ $name }}             port:               number: 80<\/code><\/pre>\n<p>\u0410\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044f <code>nginx.ingress.kubernetes.io\/canary-weight: \"30\"<\/code> \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e 30% \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u044b \u0432 \u043d\u043e\u0432\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.\u00a0<\/p>\n<p>\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u044d\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e \u043c\u043e\u0436\u043d\u043e <a href=\"https:\/\/github.com\/kubernetes\/ingress-nginx\/blob\/main\/docs\/user-guide\/nginx-configuration\/annotations.md#canary\"><u>\u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430<\/u><\/a>.<\/p>\n<h2>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c<\/h2>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u0434\u043b\u044f \u0432\u044b\u043a\u0430\u0442\u0430 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c werf, \u043f\u043e\u0434\u0440\u0430\u0437\u0443\u043c\u0435\u0432\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u043f\u0440\u043e\u0435\u043a\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c Git-\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u043c. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0432\u0435\u0442\u043a\u0443 \u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u043c \u0432 \u043d\u0435\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0432\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b:<\/p>\n<pre><code class=\"xml\">&lt;!DOCTYPE html> &lt;html> &lt;body> Wow! I'm canary nginx! &lt;\/body> &lt;\/html><\/code><\/pre>\n<p>\u0420\u0430\u0437\u0432\u0435\u0440\u043d\u0435\u043c \u043d\u043e\u0432\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u0437 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0439 \u0432\u0435\u0442\u043a\u0438 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c, \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c:<\/p>\n<pre><code class=\"bash\">$ for ((i=1;i&lt;=10;i++)); do   curl -s \"canary-example.flant.com\"; done  Hi! I'm another one typical nginx! Hi! I'm another one typical nginx! Hi! I'm another one typical nginx! Hi! I'm another one typical nginx! Hi! I'm another one typical nginx! Wow! I'm canary nginx! Wow! I'm canary nginx! Hi! I'm another one typical nginx! Hi! I'm another one typical nginx! Wow! I'm canary nginx!<\/code><\/pre>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u043d\u043e, \u0432 \u0442\u0440\u0435\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u0438\u0437 \u0434\u0435\u0441\u044f\u0442\u0438 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043e\u0442\u0432\u0435\u0442 \u043e\u0442 \u043d\u043e\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u0435\u043c\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0431\u044b\u043b\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u044b \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0435\u0439 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u041e\u0442\u043b\u0438\u0447\u043d\u043e, \u043d\u043e \u043c\u043e\u0436\u043d\u043e \u043b\u0443\u0447\u0448\u0435!<\/p>\n<h2>\u041f\u0440\u043e\u0431\u0443\u0435\u043c \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u2014 \u0441 header&#8217;\u043e\u043c<\/h2>\n<p>\u0417\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u043a\u043e\u0439 \u0442\u0440\u0430\u0444\u0438\u043a\u0430 \u043c\u0435\u0436\u0434\u0443 \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0431\u043e\u043b\u0435\u0435 \u0433\u0438\u0431\u043a\u043e, \u043d\u0435\u0436\u0435\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0440\u043e\u0446\u0435\u043d\u0442\u043d\u044b\u043c \u0441\u043e\u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u0435\u043c. \u0420\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0433\u043e header&#8217;\u0430 \u0438\u043b\u0438 cookie \u0432 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0435. \u0421\u043f\u043e\u0441\u043e\u0431\u044b \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435 \u043e\u0442\u043b\u0438\u0447\u0430\u044e\u0442\u0441\u044f \u043f\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0441 header&#8217;\u043e\u043c.<\/p>\n<p>\u041f\u0435\u0440\u0435\u0434\u0430\u0434\u0438\u043c \u0432 CI \u043a\u043b\u044e\u0447 \u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0434\u043b\u044f header\u2019\u0430 \u0438 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u043c \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 \u0432 Ingress-\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0435:<\/p>\n<pre><code>{{- if ne .Values.global.canary_deploy \"\" }}   annotations:     nginx.ingress.kubernetes.io\/canary: \"true\"     nginx.ingress.kubernetes.io\/canary-by-header: {{ $.Values.global.canary_header | quote }}     nginx.ingress.kubernetes.io\/canary-by-header-value: {{ $.Values.global.canary_header_value | quote }} {{- end }}<\/code><\/pre>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u0443\u0436\u043d\u044b\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0432 CI:<\/p>\n<pre><code class=\"yaml\">.base_converge: &amp;base_converge   stage: converge   script:     - export CI_HELM_RELEASE=${CANARY_DEPLOY}     - werf converge        --set \"global.canary_deploy=${CANARY_DEPLOY:-}\"       --set \"global.canary_header=${CANARY_HEADER:-}\"       --set \"global.canary_header_value=${CANARY_HEADER_VALUE:-}\"   except:     - schedules   tags:     - werf  Converge to canary:   &lt;&lt;: *base_converge   environment:     name: canary-example   when: manual   variables:     CANARY_DEPLOY: \"-canary\"     CANARY_HEADER: \"x-version\"     CANARY_HEADER_VALUE: \"canary\"<\/code><\/pre>\n<p>\u0420\u0430\u0437\u0432\u0435\u0440\u043d\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c, \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c:<\/p>\n<pre><code class=\"bash\">$ curl canary-example.flant.com  Hi! I'm another one typical nginx!<\/code><\/pre>\n<p>\u0412\u0441\u0451 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.\u00a0<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0434\u0430\u0434\u0438\u043c \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043d\u0443\u0436\u043d\u044b\u0439 header:<\/p>\n<pre><code class=\"bash\">$ curl -H \"x-version: canary\" canary-example.flant.com  Wow! I'm canary nginx!<\/code><\/pre>\n<p>\u0422\u043e\u0436\u0435 \u0432\u0441\u0451 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.<\/p>\n<h2>\u041a\u0430\u043a \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u00ab\u043a\u0430\u043d\u0430\u0440\u0435\u0435\u0447\u043d\u044b\u0435\u00bb\u00a0\u0440\u0435\u043b\u0438\u0437\u044b \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430<\/h2>\n<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u043b\u0438\u0448\u044c \u043e\u0434\u0438\u043d \u0438\u0437 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 canary-\u0440\u0435\u043b\u0438\u0437\u0430. \u0413\u043b\u0430\u0432\u043d\u044b\u0439 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u043a \u0442\u0430\u043a\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u2014 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Ingress. \u042d\u0442\u043e \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0434\u043b\u044f frontend-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. \u0412 \u0442\u043e \u0432\u0440\u0435\u043c\u044f \u043a\u0430\u043a \u0443 backend \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u0442\u043e\u043b\u044c\u043a\u043e Service, \u0438 \u043e\u0431\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u043a \u043d\u0435\u043c\u0443 \u0443\u0436\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430 Kubernetes.<\/p>\n<p>\u0414\u043b\u044f \u0442\u0430\u043a\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0437\u0430\u0434\u0430\u0447\u0443 canary-\u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u0440\u0435\u0448\u0430\u0435\u0442 Service Mesh \u043d\u0430\u043f\u043e\u0434\u043e\u0431\u0438\u0435 Istio \u2014 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0435\u0433\u043e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u043d\u0430\u0448\u0435\u0439 Kubernetes-\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435 <a href=\"https:\/\/deckhouse.io\/ru\/\"><u>Deckhouse<\/u><\/a> (<em>\u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0440\u0435\u0448\u0430\u0435\u0442 Istio \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 Deckhouse, \u043c\u043e\u0436\u043d\u043e <\/em><a href=\"https:\/\/deckhouse.io\/ru\/documentation\/v1\/modules\/110-istio\/\"><em><u>\u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438<\/u><\/em><\/a>). \u0414\u0440\u0443\u0433\u0438\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 <a href=\"https:\/\/istio.io\/v1.14\/blog\/2017\/0.1-canary\/\"><u>\u0432 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 Istio<\/u><\/a> \u0438 <a href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/440378\/\"><u>\u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0435<\/u><\/a>.<\/p>\n<h2>P.S.<\/h2>\n<p>\u0427\u0438\u0442\u0430\u0439\u0442\u0435 \u0442\u0430\u043a\u0436\u0435 \u0432 \u043d\u0430\u0448\u0435\u043c \u0431\u043b\u043e\u0433\u0435:<\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/471620\/\">\u00ab<u>\u0421\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u0438 \u0434\u0435\u043f\u043b\u043e\u044f \u0432 Kubernetes: rolling, recreate, blue\/green, canary, dark (A\/B-\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435)<\/u>\u00bb<\/a>;<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/545204\/\">\u00ab<u>\u041b\u0443\u0447\u0448\u0438\u0435 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438 \u0434\u043b\u044f \u0434\u0435\u043f\u043b\u043e\u044f \u0432\u044b\u0441\u043e\u043a\u043e\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0432 Kubernetes. \u0427\u0430\u0441\u0442\u044c 1<\/u>\u00bb<\/a>;<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/569612\/\">\u00ab<u>\u0427\u0442\u043e \u0436\u0434\u0430\u0442\u044c \u043e\u0442 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f Istio? (\u043e\u0431\u0437\u043e\u0440 \u0438 \u0432\u0438\u0434\u0435\u043e \u0434\u043e\u043a\u043b\u0430\u0434\u0430)<\/u>\u00bb<\/a>.<\/p>\n<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"v-portal\" style=\"display:none;\"><\/div>\n<\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/697030\/\"> https:\/\/habr.com\/ru\/company\/flant\/blog\/697030\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0422\u0435\u043c\u0430 \u00ab\u043a\u0430\u043d\u0430\u0440\u0435\u0435\u0447\u043d\u044b\u0445\u00bb (canary) \u0440\u0435\u043b\u0438\u0437\u043e\u0432 \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u043b\u0430\u0441\u044c \u0432 \u043d\u0430\u0448\u0435\u043c \u0431\u043b\u043e\u0433\u0435 \u0443\u0436\u0435 \u043d\u0435 \u0440\u0430\u0437 \u2014 \u0441\u043c. \u0441\u0441\u044b\u043b\u043a\u0438 \u0432 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438. \u041d\u043e \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043b\u0438\u0448\u043d\u0438\u043c \u043d\u0430\u043f\u043e\u043c\u043d\u0438\u0442\u044c, \u0437\u0430\u0447\u0435\u043c \u043e\u043d\u0438 \u043d\u0443\u0436\u043d\u044b.<\/p>\n<p>Canary-\u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u0433\u0440\u0443\u043f\u043f\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439. \u0413\u0440\u0443\u043f\u043f\u0430 \u0432\u044b\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u043c\u0443 \u043f\u0440\u0438\u0437\u043d\u0430\u043a\u0443. \u0422\u0435\u0441\u0442 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0437\u0430\u0442\u0440\u0430\u0433\u0438\u0432\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0435\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439. \u041d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043c\u0435\u0436\u0434\u0443 \u0434\u0432\u0443\u043c\u044f \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c\u0441\u044f \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u043e.\u00a0<\/p>\n<p>Canary-\u0440\u0435\u043b\u0438\u0437\u044b \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0442\u0441\u044f \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 Ingress-\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0442\u0430\u043a\u0438\u0445 \u0440\u0435\u043b\u0438\u0437\u043e\u0432 \u0432 Kubernetes \u043d\u0430 \u0431\u0430\u0437\u0435 <a href=\"https:\/\/github.com\/kubernetes\/ingress-nginx\"><u>Ingress NGINX Controller<\/u><\/a>.<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<blockquote>\n<p><strong>\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435<\/strong><\/p>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043a \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043e\u0431\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u0438\u043c\u0435\u043d\u043d\u043e \u0447\u0435\u0440\u0435\u0437 Ingress. \u0415\u0441\u043b\u0438 \u0432\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442 \u0441 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435\u043c \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 Service, \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u043d\u0435 \u043f\u043e\u0434\u043e\u0439\u0434\u0435\u0442.<\/p>\n<\/blockquote>\n<h2>\u0413\u043e\u0442\u043e\u0432\u0438\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432<\/h2>\n<p>\u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u0412\u043e\u0437\u044c\u043c\u0435\u043c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 NGINX, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0434\u0430\u0432\u0430\u0442\u044c \u043e\u0434\u043d\u0443 HTML-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443, \u0438 Ingress-\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440, \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u043c \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0443.<\/p>\n<p>\u041f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f \u0442\u0430\u043a\u043e\u0439 \u0447\u0430\u0440\u0442:<\/p>\n<pre><code class=\"yaml\">apiVersion: apps\/v1 kind: Deployment metadata:   name: {{ .Chart.Name }} spec:   revisionHistoryLimit: 3   selector:     matchLabels:       app: {{ .Chart.Name }}   replicas: 1   template:     metadata:       annotations:         checksum\/config: {{ include (print $.Template.BasePath \"\/10-nginx-config.yaml\") . | sha256sum }}       labels:         app: {{ .Chart.Name }}     spec:       volumes:       - name: configs         configMap:           name: {{ .Chart.Name }}-configmap       containers:       - name: nginx         imagePullPolicy: Always         image: {{ index .Values.werf.image \"nginx\" }}         lifecycle:           preStop:             exec:               command: [ \"\/bin\/bash\", \"-c\", \"sleep 5; kill -QUIT 1\" ]         command: [\"\/usr\/sbin\/nginx\", \"-g\", \"daemon off;\"]         ports:         - containerPort: 80           name: http           protocol: TCP         volumeMounts:         - name: configs           mountPath: \/etc\/nginx\/nginx.conf           subPath: nginx.conf         resources:           requests:             cpu: 50m             memory: 128Mi           limits:             memory: 128Mi --- apiVersion: v1 kind: Service metadata:   name: {{ .Chart.Name }} spec:   clusterIP: None   selector:     app: {{ .Chart.Name }}   ports:   - name: http     port: 80  --- apiVersion: v1 kind: ConfigMap metadata:   name: {{ .Chart.Name }}-configmap data:   nginx.conf: |     error_log  \/dev\/stderr;     events {       worker_connections 100000;       multi_accept on;     }     http {         charset utf-8;          server {             listen 80;             index index.html;             root \/app;             error_log \/dev\/stderr;             location \/ {                 try_files $uri \/index.html$is_args$args;             }         }     }  --- apiVersion: networking.k8s.io\/v1 kind: Ingress metadata:   name: {{ .Chart.Name }} spec:   rules:   - host: \"canary-example.flant.com\"     http:       paths:       - path: \"\/\"         pathType: Prefix         backend:           service:             name: {{ .Chart.Name }}             port:               number: 80<\/code><\/pre>\n<p>\u0412 \u043a\u043e\u0440\u0435\u043d\u044c \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0434\u0430\u0432\u0430\u0442\u044c \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440. \u041d\u0430\u0437\u043e\u0432\u0435\u043c \u0435\u0435 <code>index.html<\/code>:<\/p>\n<pre><code class=\"xml\">&lt;!DOCTYPE html> &lt;html> &lt;body> Hi! I'm another one typical nginx! &lt;\/body> &lt;\/html><\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0434\u043b\u044f \u0434\u0435\u043f\u043b\u043e\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f CI*.<\/p>\n<details class=\"spoiler\">\n<summary>* \u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0412 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d \u0434\u0435\u043f\u043b\u043e\u0439 \u043d\u0430 \u0431\u0430\u0437\u0435 GitLab CI + <a href=\"https:\/\/ru.werf.io\/\"><u>werf<\/u><\/a>.<\/p>\n<\/div>\n<\/details>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 werf \u2014 <code>werf.yaml<\/code>:<\/p>\n<pre><code class=\"yaml\">project: canary-example configVersion: 1 deploy:  helmRelease: '[[ project ]]\"'  namespace: \"[[ project ]]\"  --- image: nginx from: nginx:stable git: - add: \/   to: \/app   excludePaths:   - .helm   - werf.yaml   - .getlab-ci.yml<\/code><\/pre>\n<p>\u2026 \u0438 \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 GitLab CI \u2014 <code>.gitlab-ci.yml<\/code> **:<\/p>\n<pre><code class=\"yaml\">stages:   - converge  .base_converge: &amp;base_converge   stage: converge   script:     - werf converge    except:     - schedules   tags:     - werf  Converge base:   &lt;&lt;: *base_converge   environment:     name: canary-example   when: manual<\/code><\/pre>\n<details class=\"spoiler\">\n<summary>** \u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435<\/summary>\n<div class=\"spoiler__content\">\n<p>\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043f\u0440\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 werf \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u043e\u0431\u0440\u0430\u0437\u043e\u0432 \u0438 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/ru.werf.io\/documentation\/v1.2\/quickstart.html\"><u>\u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438<\/u><\/a>. \u0412\u0441\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0435 \u043a\u043e\u0434\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0447\u0430\u0440\u0442\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 <a href=\"https:\/\/github.com\/flant\/examples\/tree\/master\/2022\/10-canary-example\"><u>\u0432 \u043d\u0430\u0448\u0435\u043c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/u><\/a>.<\/p>\n<\/div>\n<\/details>\n<p>\u0420\u0430\u0437\u0432\u0435\u0440\u043d\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0435, \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0432 CI, \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c, \u0447\u0442\u043e \u043e\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442:<\/p>\n<pre><code class=\"bash\">$ curl canary-example.flant.com  Hi! I'm another one typical nginx!<\/code><\/pre>\n<p>\u041e\u0442\u043b\u0438\u0447\u043d\u043e!\u00a0<\/p>\n<p>\u041f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 canary-\u0440\u0435\u043b\u0438\u0437\u043e\u0432.<\/p>\n<h2>\u0414\u0435\u043b\u0430\u0435\u043c \u00ab\u043a\u0430\u043d\u0430\u0440\u0435\u0435\u0447\u043d\u044b\u0439\u00bb \u0440\u0435\u043b\u0438\u0437<\/h2>\n<p>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043c \u0434\u0432\u0435 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f \u0434\u0432\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 Helm-\u0440\u0435\u043b\u0438\u0437\u0430.\u00a0<\/p>\n<p>\u041c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u0440\u0430\u043d\u0435\u0435 CI, \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u0432 \u043d\u0435\u0433\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 Job \u0434\u043b\u044f canary-\u0434\u0435\u043f\u043b\u043e\u044f \u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <code>$CANARY_DEPLOY<\/code>, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0432 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 Helm-\u0440\u0435\u043b\u0438\u0437\u0430.\u00a0<\/p>\n<p>\u0412\u043d\u0435\u0441\u0435\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0444\u0430\u0439\u043b\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u2014 \u0432 <code>.gitlab-ci.yml<\/code>:<\/p>\n<pre><code class=\"yaml\">stages:   - converge  .base_converge: &amp;base_converge   stage: converge   script:     - export CI_HELM_RELEASE=${CANARY_DEPLOY}     - werf converge        --set \"global.canary_deploy=${CANARY_DEPLOY:-}\"   except:     - schedules   tags:     - werf  Converge base:   &lt;&lt;: *base_converge   environment:     name: canary-example   when: manual   variables:     CANARY_DEPLOY: \"\"  Converge canary::   &lt;&lt;: *base_converge   environment:     name: canary-example   when: manual   variables:     CANARY_DEPLOY: \"-canary\"<\/code><\/pre>\n<p>\u2026 \u0438 \u0432 <code>werf.yaml<\/code>:<\/p>\n<pre><code class=\"yaml\">project: canary-example configVersion: 1 deploy:  helmRelease: '[[ project ]]{{ env \"CI_HELM_RELEASE\" }}'  namespace: \"[[ project ]]\"  --- image: nginx from: nginx:stable git: - add: \/   to: \/app   excludePaths:   - .helm   - werf.yaml   - .getlab-ci.yml<\/code><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u0432 <code>.gitlab-ci.yml<\/code> \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f <code>$CANARY_DEPLOY<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043e\u0431\u043e\u0438\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430\u0445 \u0434\u0435\u043f\u043b\u043e\u044f (<code>base<\/code> \u0438 <code>canary<\/code>). \u041d\u043e \u0432 \u043f\u0435\u0440\u0432\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u043d\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043b\u0438\u0448\u044c \u043f\u0443\u0441\u0442\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443, \u0430 \u043f\u0440\u0438 canary \u2014 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>-canary<\/code>. \u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0440\u0435\u043b\u0438\u0437 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f <code>nginx-example<\/code>, \u0430 canary-\u0440\u0435\u043b\u0438\u0437 \u2014 <code>nginx-example-canary<\/code>.<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u043d\u0430 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0432 \u0440\u0435\u043b\u0438\u0437\u0430\u0445 \u043d\u0435 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u043b\u0438, \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u043c \u0447\u0430\u0440\u0442. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043f\u043e \u0448\u0430\u0431\u043b\u043e\u043d\u0443 \u00ab\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0447\u0430\u0440\u0442\u0430 + \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 <code>global.canary_deploy<\/code>\u00bb:<\/p>\n<pre><code class=\"yaml\">{{ $name := printf \"%s%s\" (.Chart.Name) (.Values.global.canary_deploy) }} apiVersion: apps\/v1 kind: Deployment metadata:   name: {{ $name }} spec:   revisionHistoryLimit: 3   selector:     matchLabels:       app: {{ $name }}   replicas: 1   template:     metadata:       annotations:         checksum\/config: {{ include (print $.Template.BasePath \"\/10-nginx-config.yaml\") . | sha256sum }}       labels:         app: {{ $name }}     spec:       imagePullSecrets:       - name: registrysecret       volumes:       - name: configs         configMap:           name: {{ $name }}-configmap       containers:       - name: nginx         imagePullPolicy: Always         image: {{ index .Values.werf.image \"nginx\" }}         lifecycle:           preStop:             exec:               command: [ \"\/bin\/bash\", \"-c\", \"sleep 5; kill -QUIT 1\" ]         command: [\"\/usr\/sbin\/nginx\", \"-g\", \"daemon off;\"]         ports:         - containerPort: 80           name: http           protocol: TCP         volumeMounts:         - name: configs           mountPath: \/etc\/nginx\/nginx.conf           subPath: nginx.conf         resources:           requests:             cpu: 50m             memory: 128Mi           limits:             memory: 128Mi --- apiVersion: v1 kind: Service metadata:   name:{{ $name }} spec:   clusterIP: None   selector:     app: {{ $name }}   ports:   - name: http     port: 80  --- apiVersion: v1 kind: ConfigMap metadata:   name: {{ $name }}-configmap data:   nginx.conf: |     error_log  \/dev\/stderr;     events {       worker_connections 100000;       multi_accept on;     }     http {         charset utf-8;          server {             listen 80;             index index.html;             root \/app;             error_log \/dev\/stderr;             location \/ {                 try_files $uri \/index.html$is_args$args;             }         }     }<\/code><\/pre>\n<p>\u0412 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u0430 Ingress \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442, \u043a\u0430\u043a\u043e\u0439 \u043f\u0440\u043e\u0446\u0435\u043d\u0442 \u0442\u0440\u0430\u0444\u0438\u043a\u0430 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043d\u0430\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0432 canary-\u0432\u0435\u0440\u0441\u0438\u044e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"yaml\">{{ $name := printf \"%s%s\" (.Chart.Name) (.Values.global.canary_deploy) }} apiVersion: networking.k8s.io\/v1 kind: Ingress metadata:   name: {{ $name }} {{- if ne .Values.global.canary_deploy \"\" }}   annotations:    nginx.ingress.kubernetes.io\/canary: \"true\"    nginx.ingress.kubernetes.io\/canary-weight: \"30\" {{- end }} spec:   rules:   - host: \"canary-example.flant.com\"     http:       paths:       - path: \"\/\"         pathType: Prefix         backend:           service:             name: {{ $name }}             port:               number: 80<\/code><\/pre>\n<p>\u0410\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044f <code>nginx.ingress.kubernetes.io\/canary-weight: \"30\"<\/code> \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e 30% \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u044b \u0432 \u043d\u043e\u0432\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.\u00a0<\/p>\n<p>\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u044d\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e \u043c\u043e\u0436\u043d\u043e <a href=\"https:\/\/github.com\/kubernetes\/ingress-nginx\/blob\/main\/docs\/user-guide\/nginx-configuration\/annotations.md#canary\"><u>\u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430<\/u><\/a>.<\/p>\n<h2>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c<\/h2>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u0434\u043b\u044f \u0432\u044b\u043a\u0430\u0442\u0430 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c werf, \u043f\u043e\u0434\u0440\u0430\u0437\u0443\u043c\u0435\u0432\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u043f\u0440\u043e\u0435\u043a\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c Git-\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u043c. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0432\u0435\u0442\u043a\u0443 \u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u043c \u0432 \u043d\u0435\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0432\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b:<\/p>\n<pre><code class=\"xml\">&lt;!DOCTYPE html> &lt;html> &lt;body> Wow! I'm canary nginx! &lt;\/body> &lt;\/html><\/code><\/pre>\n<p>\u0420\u0430\u0437\u0432\u0435\u0440\u043d\u0435\u043c \u043d\u043e\u0432\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u0437 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0439 \u0432\u0435\u0442\u043a\u0438 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c, \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c:<\/p>\n<pre><code class=\"bash\">$ for ((i=1;i&lt;=10;i++)); do   curl -s \"canary-example.flant.com\"; done  Hi! I'm another one typical nginx! Hi! I'm another one typical nginx! Hi! I'm another one typical nginx! Hi! I'm another one typical nginx! Hi! I'm another one typical nginx! Wow! I'm canary nginx! Wow! I'm canary nginx! Hi! I'm another one typical nginx! Hi! I'm another one typical nginx! Wow! I'm canary nginx!<\/code><\/pre>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u043d\u043e, \u0432 \u0442\u0440\u0435\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u0438\u0437 \u0434\u0435\u0441\u044f\u0442\u0438 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043e\u0442\u0432\u0435\u0442 \u043e\u0442 \u043d\u043e\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u0435\u043c\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0431\u044b\u043b\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u044b \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0435\u0439 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u041e\u0442\u043b\u0438\u0447\u043d\u043e, \u043d\u043e \u043c\u043e\u0436\u043d\u043e \u043b\u0443\u0447\u0448\u0435!<\/p>\n<h2>\u041f\u0440\u043e\u0431\u0443\u0435\u043c \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u2014 \u0441 header&#8217;\u043e\u043c<\/h2>\n<p>\u0417\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u043a\u043e\u0439 \u0442\u0440\u0430\u0444\u0438\u043a\u0430 \u043c\u0435\u0436\u0434\u0443 \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0431\u043e\u043b\u0435\u0435 \u0433\u0438\u0431\u043a\u043e, \u043d\u0435\u0436\u0435\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-340714","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/340714","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=340714"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/340714\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=340714"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=340714"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=340714"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}