ЁЯПл The SchoolтА║ЁЯдЦ ArgoCDтА║ЁЯУо рдзрдбрд╛ 03 тАФ CI/CD push: courier robot рддреБрдордЪреНрдпрд╛рд╕рд╛рдареА deploy рдХрд░рддреЛ
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯУо рдзрдбрд╛ 03 тАФ CI/CD push: courier robot рддреБрдордЪреНрдпрд╛рд╕рд╛рдареА deploy рдХрд░рддреЛ

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 03 ┬╖ рдорд╛рдЧреЗ: lesson-02-drift-problem ┬╖ рдкреБрдвреЗ: lesson-04-limits-of-push


ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ

рдзрдбреЗ 01тАУ02, рдЖрдгрд┐ рддреНрдпрд╛рд╕реЛрдмрдд рдкрд╣рд┐рд▓рд╛ рдЦрд░рд╛ рдЙрдкрд╛рдп: рдкреНрд░рддреНрдпреЗрдХ push рд╡рд░ test, build рдЖрдгрд┐ deploy рдХрд░рдгрд╛рд░реА CI/CD pipeline тАФ рдореНрд╣рдгрдЬреЗ push model, рдЬреНрдпрд╛рдд рдмрд╛рд╣реЗрд░рдЪреА рдПрдЦрд╛рджреА system рдмрджрд▓ рдЬреЛрд░рд╛рдиреЗ cluster рдордзреНрдпреЗ рдврдХрд▓рддреЗ.

ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ

рдореБрд▓реЗ рд╣рд╛рддрд╛рдиреЗ рдЧреГрд╣рдкрд╛рда рдкреЛрд╣реЛрдЪрд╡рддрд╛рдд рдпрд╛рд▓рд╛ рд╢рд╛рд│рд╛ рдХрдВрдЯрд╛рд│рд▓реА, рдореНрд╣рдгреВрди рддрд┐рдиреЗ рдПрдХ courier robot ЁЯУо рдХрд╛рдорд╛рд╡рд░ рдареЗрд╡рд▓рд╛. рдЖрддрд╛ рддреБрдореНрд╣реА рдлрдХреНрдд рддреБрдордЪрд╛ рдЧреГрд╣рдкрд╛рда рдЯрдкрд╛рд▓рдкреЗрдЯреАрдд рдЯрд╛рдХрддрд╛ (git push) рдЖрдгрд┐ robot рджрд░ рд╡реЗрд│реА рдЕрдЧрджреА рддреНрдпрд╛рдЪ рдкрд╛рдпрд▒реНрдпрд╛ рдХрд░рддреЛ:

  1. рддрдкрд╛рд╕рддреЛ тЬЕ тАФ рд╢реБрджреНрдзрд▓реЗрдЦрди рдЖрдгрд┐ рдЧрдгрд┐рдд (tests рдЪрд╛рд▓рд╡рддреЛ). рд╡рд╛рдИрдЯ рдЧреГрд╣рдкрд╛рда рдХрдзреАрдЪ рдЯрдкрд╛рд▓рдЦреЛрд▓реАрддреВрди рдмрд╛рд╣реЗрд░ рдкрдбрдд рдирд╛рд╣реА.
  2. рдЭреЗрд░реЙрдХреНрд╕ рдХрд╛рдврддреЛ ЁЯН▒ тАФ рдЕрдзрд┐рдХреГрдд рдкреНрд░рдд (container image build рдХрд░рддреЛ).
  3. рдкреНрд░рдд рдЬрдкреВрди рдареЗрд╡рддреЛ ЁЯЧДя╕П тАФ рдХрдкрд╛рдЯрд╛рдд (registry рд▓рд╛ push рдХрд░рддреЛ).
  4. рдкреЛрд╣реЛрдЪрд╡рддреЛ ЁЯЪЪ тАФ рдЧрд╛рдбреА рдЪрд╛рд▓рд╡рдд рд╢рд╛рд│реЗрдд рдЬрд╛рддреЛ, рд╕реНрд╡рддрдГрдХрдбрдЪреНрдпрд╛ deployment credentials ЁЯФС рдиреЗ рджрд╛рд░ рдЙрдШрдбрддреЛ (рд╕рдЧрд│реНрдпрд╛рдд рд╡рд╛рдИрдЯ рдореНрд╣рдгрдЬреЗ рд╕рд╛рдард╡рд▓реЗрд▓реЗ kubeconfig, рд╕рдЧрд│реНрдпрд╛рдд рдЪрд╛рдВрдЧрд▓реЗ рдореНрд╣рдгрдЬреЗ рдереЛрдбреНрдпрд╛ рдХрд╛рд│рд╛рд╕рд╛рдареАрдЪрд╛ OIDC badge), рдЖрдгрд┐ рд╕рдЧрд│реЗ рдЬрд╛рдЧреЗрд╡рд░ рд▓рд╛рд╡рддреЛ (kubectl apply).

рдЦреВрдк рдореЛрдареА рд╕реБрдзрд╛рд░рдгрд╛! рдЖрддрд╛ рд╡рд┐рд╕рд░рд▓реЗрд▓реНрдпрд╛ рдкрд╛рдпрд▒реНрдпрд╛ рдирд╛рд╣реАрдд, "рдорд╛рдЭреНрдпрд╛ machine рд╡рд░ рдЪрд╛рд▓рддреЗ" рдирд╛рд╣реА, рдЖрдгрд┐ рдЯрдкрд╛рд▓рдЦреЛрд▓реАрдд рдкреЛрд╣реЛрдЪрд╡рдгреНрдпрд╛рдЪреА рдиреЛрдВрджрд╡рд╣реА рдЖрд╣реЗ. рдкрдг рддреНрдпрд╛ credentials рд╡рд░ рд▓рдХреНрд╖ рдареЗрд╡рд╛ тАФ рдЖрдгрд┐ robot рдирд┐рдШреВрди рдЧреЗрд▓реНрдпрд╛рд╡рд░ рдирдВрддрд░ рдХрд╛рдп рд╣реЛрддреЗ рддреНрдпрд╛рд╡рд░рд╣реАтАж (рдзрдбрд╛ 04 ЁЯШИ)

ЁЯЧ║я╕П рдЖрдХреГрддреА

flowchart LR
    dev["ЁЯзСтАНЁЯТ╗ dev<br/>git push"]
    subgraph ci["ЁЯУо the courier robot - CI/CD"]
        t["тЬЕ test"] --> b["ЁЯН▒ build image"] --> r["ЁЯЧДя╕П registry"]
    end
    cluster["ЁЯПл cluster<br/>kubectl apply from OUTSIDE<br/>with deployment credentials ЁЯФС"]
    dev -->|"1"| ci
    r -->|"3 PUSH deploy"| cluster
    t -.->|"2 bad code stops here"| dev

тЭУ рдХрд╛рдп

ЁЯдФ рдХрд╛

Pipeline рдзрдбрд╛ 01 рдордзрд▓реНрдпрд╛ рдорд╛рдгрд╕рд╛рдВрдЪреНрдпрд╛ рд╕рдорд╕реНрдпрд╛ рд╕реЛрдбрд╡рддреЗ: рд╡рд┐рд╕рд░рд▓реЗрд▓реНрдпрд╛ рдкрд╛рдпрд▒реНрдпрд╛, рд╡рдЧрд│рд▓реЗрд▓реНрдпрд╛ tests, рдПрдХрд╛рдЪ рд╡реНрдпрдХреНрддреАрдХрдбрдЪреЗ рдЬреНрдЮрд╛рди, рдкреЛрд╣реЛрдЪрд╡рдгреНрдпрд╛рдЪреА рдиреЛрдВрдж рдирд╕рдгреЗ. рдкреНрд░рддреНрдпреЗрдХ deploy рдЖрддрд╛ рдПрдЦрд╛рджреНрдпрд╛ commit рдкрд░реНрдпрдВрдд рдорд╛рдЧреЛрд╡рд╛ рдШреЗрддрд╛ рдпреЗрддреЛ рдЖрдгрд┐ рдкреБрдиреНрд╣рд╛ рдХрд░рддрд╛ рдпреЗрддреЛ. рдПрд╡рдвреЗрдЪ рд╣реА рдПрдХ рдкреНрд░рдЪрдВрдб, рдЦрд░реА рд╕реБрдзрд╛рд░рдгрд╛ рдЖрд╣реЗ тАФ рдмрд╣реБрддреЗрдХ teams рдиреА ArgoCD рдЪрд╛ рд╡рд┐рдЪрд╛рд░ рдХрд░рдгреНрдпрд╛рдЖрдзреА рдЗрдердкрд░реНрдпрдВрдд рдкреЛрд╣реЛрдЪрд╛рдпрд▓рд╛ рд╣рд╡реЗ.

ЁЯФз рдХрд╕реЗ (рдПрдХ рдЫреЛрдЯреЗ рдЙрджрд╛рд╣рд░рдг)

GitHub Actions рдордзрд▓рд╛ push-style deploy job рдЕрд╕рд╛ рджрд┐рд╕рддреЛ (рдлрдХреНрдд рдЙрджрд╛рд╣рд░рдгрд╛рд╕рд╛рдареА тАФ рдЦрд░реЗ cluster credentials commit рдХрд░реВ рдирдХрд╛, CI secrets рд╡рд╛рдкрд░рд╛):

# .github/workflows/deploy.yml (example тАФ the k8s course uses CircleCI, same idea)
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: echo "$KUBECONFIG_DATA" | base64 -d > kubeconfig   # ЁЯФС deployment credentials тАФ here a stored kubeconfig; see the OIDC note
        env: { KUBECONFIG_DATA: ${{ secrets.KUBECONFIG_DATA }} }
      - run: KUBECONFIG=kubeconfig kubectl apply -f k8s/        # push it in
      - run: KUBECONFIG=kubeconfig kubectl -n gitops-school rollout status deploy/hello-school

рдЖрддреНрддрд╛ рдХрд╛рдп рдЭрд╛рд▓реЗ рддреЗ рд▓рдХреНрд╖рд╛рдд рдШреНрдпрд╛: cluster рдЪреА key рдЖрддрд╛ cluster рдЪреНрдпрд╛ рдмрд╛рд╣реЗрд░ рд░рд╛рд╣рддреЗ, CI system рдЪреНрдпрд╛ secret store рдордзреНрдпреЗ. рд╣реЗ рд▓рдХреНрд╖рд╛рдд рдареЗрд╡рд╛.

ЁЯкк рд╕рд╛рдард╡рд▓реЗрд▓реА key рд╡рд┐рд░реБрджреНрдз OIDC. рд╣реЗ рдЙрджрд╛рд╣рд░рдг kubeconfig CI secret рдореНрд╣рдгреВрди рд╕рд╛рдард╡рддреЗ тАФ рд╕рдЧрд│реНрдпрд╛рдд рд╕реЛрдкрд╛ рдЖрдгрд┐ рд╕рдЧрд│реНрдпрд╛рдд рдХрдореА рд╕реБрд░рдХреНрд╖рд┐рдд рдкреНрд░рдХрд╛рд░. рдЕрдзрд┐рдХ рдЪрд╛рдВрдЧрд▓рд╛ рдкреНрд░рдХрд╛рд░ рдореНрд╣рдгрдЬреЗ CI/CD рд╢рд╛рд│рд╛ рдЬреЗ рд╢рд┐рдХрд╡рддреЗ тАФ рдЖрдгрд┐ Docker рд╢рд╛рд│реЗрдЪрд╛ рдзрдбрд╛ 12 ECR рд╕рд╛рдареА рдЬреЗ рдХрд░рддреЛ: job OIDC рджреНрд╡рд╛рд░реЗ рдЖрдкрд▓реА рдУрд│рдЦ рд╕рд┐рджреНрдз рдХрд░рддреЛ рдЖрдгрд┐ рддреНрдпрд╛рд▓рд╛ рдереЛрдбреНрдпрд╛ рдХрд╛рд│рд╛рдЪреЗ credential рдорд┐рд│рддреЗ (EKS рд╕рд╛рдареА: role-to-assume рдирдВрддрд░ aws eks update-kubeconfig). CI рдордзреНрдпреЗ рджреАрд░реНрдШрдХрд╛рд│ рдЯрд┐рдХрдгрд╛рд░реА key рдмрд╕реВрди рд░рд╛рд╣рдд рдирд╛рд╣реА тАФ рдкрдг pipeline рд▓рд╛ рдмрд╛рд╣реЗрд░реВрди рдЖрдд рдпреЗрдгреНрдпрд╛рдЪрд╛ рдХреЛрдгрддрд╛ рддрд░реА рдорд╛рд░реНрдЧ рд▓рд╛рдЧрддреЛрдЪ, рдЖрдгрд┐ рддреНрдпрд╛рдЪрд╛ рдЕрд░реНрде рдХрд╛рдп рд╣рд╛ рдзрдбрд╛ 04 рдЪрд╛ рд╡рд┐рд╖рдп рдЖрд╣реЗ.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛ (robot рдЪреЗ local simulation)

# play courier robot yourself тАФ the exact steps a pipeline runs:
kubectl diff -f k8s/ || true                          # 1. what would change?
kubectl apply -f k8s/                                 # 2. deliver
kubectl -n gitops-school rollout status deploy/hello-school   # 3. confirm it landed

# the pipeline's superpower is that it NEVER does it differently.
# your superpower is that you now know each step it automates.

тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ

Robot рдЪреЗ local simulation рдХрд░рддрд╛рдирд╛, рд╢реЗрд╡рдЯрдЪреА command тАФ kubectl -n gitops-school rollout status deploy/hello-school тАФ successfully rolled out рдЫрд╛рдкрддреЗ. рдЦрд▒реНрдпрд╛ pipeline рдордзреНрдпреЗ: рд╣рд┐рд░рд╡рд╛ job, рдЖрдгрд┐ kubectl -n gitops-school get deploy hello-school -o jsonpath='{.spec.template.spec.containers[0].image}' рдиреЗрдордХрд╛ рддреНрдпрд╛ job рдиреЗ build рдХреЗрд▓реЗрд▓рд╛ tag рджрд╛рдЦрд╡рддреЗ.

ЁЯз╣ рд╕рд╛рдлрд╕рдлрд╛рдИ

рдХрд╛рд╣реАрдЪ install рдЭрд╛рд▓реЗ рдирд╛рд╣реА. рддреБрдореНрд╣реА fork рд╡рд░ рдЦрд░рд╛ workflow рдмрдирд╡рд▓рд╛ рдЕрд╕реЗрд▓, рддрд░ рдХрд╛рдо рдЭрд╛рд▓реНрдпрд╛рд╡рд░ рд╕рд╛рдард╡рд▓реЗрд▓реЗ kubeconfig secret delete рдХрд░рд╛ тАФ рддреЗ рддреБрдордЪреНрдпрд╛ cluster рдЪреЗ credential рдЖрд╣реЗ, рдЕрдЧрджреА local cluster рдЕрд╕рд▓реЗ рддрд░реА.

тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ рдЖрд╣реЗ: рдЦрд▒реНрдпрд╛ deployments рдкреИрдХреА рдмрд╣реБрддреЗрдХ push pipelines рдЕрд╕рддрд╛рдд рдЖрдгрд┐ рддреНрдпрд╛ рд╣рд╛рддрд╛рдиреЗ deploy рдХрд░рдгреНрдпрд╛рдкреЗрдХреНрд╖рд╛ рдЦрд░реА рд╕реБрдзрд╛рд░рдгрд╛ рдЖрд╣реЗрдд. ArgoCD рдХрдбреЗ рд╡рд│рдгреНрдпрд╛рдЖрдзреА рддреНрдпрд╛ рдиреАрдЯ рдХрд░рд╛ тАФ рдереЛрдбреНрдпрд╛ рдХрд╛рд│рд╛рдЪреЗ credentials, tag = commit SHA, рдлрд╛рдЯрдХ рдореНрд╣рдгреВрди rollout status. GitOps рдПрдХ reconcile loop рдЬреЛрдбрддреЗ; рддреЗ CI рдЪреА рдЬрд╛рдЧрд╛ рдШреЗрдд рдирд╛рд╣реА.

тПня╕П рдкреБрдвреЗ

Courier рдЫрд╛рди рдЖрд╣реЗ тАФ рдордЧ рдпрд╛ рдХреЛрд░реНрд╕рдЪрд╛ рднрд╛рдЧ 2 рдХрд╛ рдЖрд╣реЗ? рдХрд╛рд░рдг courier рдЬреЗ рдХрд░реВ рд╢рдХрдд рдирд╛рд╣реА рддреНрдпрд╛рдореБрд│реЗ. рдзрдбрд╛ 04 рддреНрдпрд╛ рддреНрд░реБрдЯреА рдореЛрдЬрддреЛ.

git checkout lesson-04-limits-of-push

ЁЯУо Lesson 03 тАФ CI/CD push: the courier robot deploys for you

ЁЯУН You are here: Lesson 03 of 12 ┬╖ Previous: lesson-02-drift-problem ┬╖ Next: lesson-04-limits-of-push


ЁЯУж What's in this branch

Lessons 01тАУ02, plus the first real fix: a CI/CD pipeline that tests, builds and deploys on every push тАФ the push model, where an outside system shoves changes into the cluster.

ЁЯзТ Explain like I'm 5

The school got tired of kids hand-delivering homework, so it hired a courier robot ЁЯУо. Now you just drop your homework in the mailbox (git push) and the robot does the same steps, every single time:

  1. Checks it тЬЕ тАФ spelling and math (runs the tests). Bad homework never leaves the mailroom.
  2. Photocopies it ЁЯН▒ тАФ the official copy (builds the container image).
  3. Files the copy ЁЯЧДя╕П тАФ into the cabinet (pushes to the registry).
  4. Delivers it ЁЯЪЪ тАФ drives to school, unlocks the door with the deployment credentials it carries ЁЯФС (a stored kubeconfig at worst, a short-lived OIDC badge at best), and puts everything in place (kubectl apply).

Huge upgrade! No more forgotten steps, no more "works on my machine", and there's a delivery log in the mailroom. But keep an eye on those credentials тАФ and on what happens after the robot drives awayтАж (lesson 04 ЁЯШИ)

ЁЯЧ║я╕П Diagram

flowchart LR
    dev["ЁЯзСтАНЁЯТ╗ dev<br/>git push"]
    subgraph ci["ЁЯУо the courier robot - CI/CD"]
        t["тЬЕ test"] --> b["ЁЯН▒ build image"] --> r["ЁЯЧДя╕П registry"]
    end
    cluster["ЁЯПл cluster<br/>kubectl apply from OUTSIDE<br/>with deployment credentials ЁЯФС"]
    dev -->|"1"| ci
    r -->|"3 PUSH deploy"| cluster
    t -.->|"2 bad code stops here"| dev

тЭУ What

ЁЯдФ Why

The pipeline fixes the human problems from lesson 01: forgotten steps, skipped tests, single-person knowledge, no delivery record. Every deploy is now traceable to a commit and repeatable. This alone is a massive, genuine upgrade тАФ most teams should get here before even thinking about ArgoCD.

ЁЯФз How (a minimal example)

A push-style deploy job in GitHub Actions looks like this (illustrative тАФ don't commit real cluster credentials, use CI secrets):

# .github/workflows/deploy.yml (example тАФ the k8s course uses CircleCI, same idea)
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: echo "$KUBECONFIG_DATA" | base64 -d > kubeconfig   # ЁЯФС deployment credentials тАФ here a stored kubeconfig; see the OIDC note
        env: { KUBECONFIG_DATA: ${{ secrets.KUBECONFIG_DATA }} }
      - run: KUBECONFIG=kubeconfig kubectl apply -f k8s/        # push it in
      - run: KUBECONFIG=kubeconfig kubectl -n gitops-school rollout status deploy/hello-school

Note what just happened: the cluster's key now lives outside the cluster, in the CI system's secret store. Remember that.

ЁЯкк Stored key vs OIDC. This example stores a kubeconfig as a CI secret тАФ the simplest and least safe shape. The better shape is what the CI/CD school teaches тАФ and the Docker school's lesson 12 does for ECR: the job proves who it is via OIDC and receives a short-lived credential (for EKS: aws eks update-kubeconfig after role-to-assume). No long-lived key sits in CI тАФ but the pipeline still needs some way in from outside, and lesson 04 is about what that means.

ЁЯзк Try it (simulate the robot locally)

# play courier robot yourself тАФ the exact steps a pipeline runs:
kubectl diff -f k8s/ || true                          # 1. what would change?
kubectl apply -f k8s/                                 # 2. deliver
kubectl -n gitops-school rollout status deploy/hello-school   # 3. confirm it landed

# the pipeline's superpower is that it NEVER does it differently.
# your superpower is that you now know each step it automates.

тЬЕ Verify тАФ what you should see

Simulating the robot locally, the last command тАФ kubectl -n gitops-school rollout status deploy/hello-school тАФ prints successfully rolled out. In a real pipeline: a green job, and kubectl -n gitops-school get deploy hello-school -o jsonpath='{.spec.template.spec.containers[0].image}' shows exactly the tag that job built.

ЁЯз╣ Clean up

Nothing was installed. If you created a real workflow on a fork, delete the stored kubeconfig secret when you are done тАФ it is a credential to your cluster, even a local one.

тЪая╕П Common mistakes

ЁЯПн Why this matters in production: push pipelines are the majority of real deployments and a genuine upgrade over hand deploys. Do them well тАФ short-lived credentials, tag = commit SHA, rollout status as the gate тАФ before reaching for ArgoCD. GitOps adds a reconcile loop; it does not replace CI.

тПня╕П Next

The courier is great тАФ so why does Part 2 of this course exist? Because of what the courier can't do. Lesson 04 counts the gaps.

git checkout lesson-04-limits-of-push
тЖР Previousdrift problemNext тЖТlimits of push

This page is the lesson's README from the lesson-03-cicd-push branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.