ЁЯПл The SchoolтА║ЁЯН▒ DockerтА║ЁЯз╣ рдзрдбрд╛ 11 тАФ Push, pull рдЖрдгрд┐ lifecycle: рдбрдмреЗ рдареЗрд╡рдгреЗ рдЖрдгрд┐ рд╕рдлрд╛рдИ рдХрд░реНрдордЪрд╛рд░реА
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯз╣ рдзрдбрд╛ 11 тАФ Push, pull рдЖрдгрд┐ lifecycle: рдбрдмреЗ рдареЗрд╡рдгреЗ рдЖрдгрд┐ рд╕рдлрд╛рдИ рдХрд░реНрдордЪрд╛рд░реА

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 11 ┬╖ рдорд╛рдЧреЗ: lesson-10-ecr-setup ┬╖ рдкреБрдвреЗ: lesson-12-ci-to-cloud


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

рдзрдбреЗ 01тАУ10, рдЖрдгрд┐ рддреНрдпрд╛рд╢рд┐рд╡рд╛рдп: ECR рдЪрд╛ рд░реЛрдЬрдЪрд╛ workflow тАФ рдкреВрд░реНрдг рдкрддреНрддреНрдпрд╛рдиреЗ tag рдХрд░рд╛, push рдХрд░рд╛, pull рдХрд░рд╛ тАФ рдЖрдгрд┐ рддреБрдордЪрд╛ locker рдЬреБрдиреНрдпрд╛ рдкреБрд░рд╛рдгреНрдпрд╛ рдЬреЗрд╡рдгрд╛рдиреЗ рднрд░реВ рди рджреЗрдгрд╛рд░реА lifecycle policy. рдЦрд░реА file:

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

рдмрдБрдХреЗрдд рдбрдмрд╛ рдареЗрд╡рдгреНрдпрд╛рдЪрд╛ рдПрдХ рдирд┐рдпрдо рдЖрд╣реЗ рдЬреНрдпрд╛рд╡рд░ рд▓реЛрдХ рдиреЗрд╣рдореА рдЕрдбрдЦрд│рддрд╛рдд: рд▓реЗрдмрд▓рд╡рд░ рдкреВрд░реНрдг рдкрддреНрддрд╛ рдЕрд╕рд╛рдпрд▓рд╛рдЪ рд╣рд╡рд╛ ЁЯП╖я╕П. рдлрдХреНрдд hello-school:v1 рд▓реЗрдмрд▓ рдЕрд╕рд▓реЗрд▓рд╛ рдбрдмрд╛ рдмрдБрдХ рд╕реНрд╡реАрдХрд╛рд░рдд рдирд╛рд╣реА тАФ рдХреЛрдгрддреА рдмрдБрдХ? рдХреЛрдгрддреА рд╢рд╛рдЦрд╛? рдХреЛрдгрддрд╛ locker? рд▓реЗрдмрд▓рд╡рд░ рдЕрд╕реЗ рд▓рд┐рд╣рд┐рд▓реЗрд▓реЗ рд╣рд╡реЗ:

123456789012.dkr.ecr.ap-south-1.amazonaws.com/hello-school:v1 (рдмрдБрдХ ┬╖ рд╢рд╛рдЦрд╛ ┬╖ locker ┬╖ рдбрдмреНрдпрд╛рдЪреЗ рдирд╛рд╡)

docker tag рдиреЗрдордХреЗ рд╣реЗрдЪ рдХрд░рддреЗ тАФ рддреЗ рдХрд╛рд╣реАрд╣реА copy рдХрд░рдд рдирд╛рд╣реА, рдлрдХреНрдд рддреНрдпрд╛рдЪ рдбрдмреНрдпрд╛рд╡рд░ рджреБрд╕рд░реЗ, рдкреВрд░реНрдг рдкрддреНрддрд╛ рдЕрд╕рд▓реЗрд▓реЗ рд▓реЗрдмрд▓ рд▓рд┐рд╣рд┐рддреЗ. рдордЧ docker push рддреЗ рд▓реЗрдмрд▓ рд╡рд╛рдЪрддреЛ рдЖрдгрд┐ рдиреЗрдордХреЗ рдХреБрдареЗ рдкреЛрд╣реЛрдЪрд╡рд╛рдпрдЪреЗ рддреЗ рддреНрдпрд╛рд▓рд╛ рдХрд│рддреЗ.

рдЖрдгрд┐ рд╕рдлрд╛рдИ рдХрд░реНрдордЪрд╛рд░реА ЁЯз╣: рдкреНрд░рддреНрдпреЗрдХ push рдПрдХ рдбрдмрд╛ рдЬреЛрдбрддреЛ, рдХрд╛рдпрдордЪрд╛. рд╡рд░реНрд╖рднрд░ рд░реЛрдЬ deploys = рдмрд╣реБрддреЗрдХ рдордореА рдЭрд╛рд▓реЗрд▓реНрдпрд╛ рдЬреЗрд╡рдгрд╛рдЪреЗ 365 рдбрдмреЗ, рдЖрдгрд┐ рдмрдБрдХ рдХрдкреНрдкреНрдпрд╛рдЪреНрдпрд╛ рдкреНрд░рддреНрдпреЗрдХ рд╕реЗрдВрдЯреАрдореАрдЯрд░рдЪреЗ рдкреИрд╕реЗ рдШреЗрддреЗ. lifecycle policy рдореНрд╣рдгрдЬреЗ рд╕рдлрд╛рдИ рдХрд░реНрдордЪрд╛рд▒реНрдпрд╛рд▓рд╛ рджрд┐рд▓реЗрд▓реНрдпрд╛ рдХрд╛рдпрдордЪреНрдпрд╛ рд╕реВрдЪрдирд╛: "рд╕рд░реНрд╡рд╛рдд рдирд╡реЗ 10 рдбрдмреЗ рдареЗрд╡рд╛; рдмрд╛рдХреАрдЪреЗ рд╢рд╛рдВрддрдкрдгреЗ expire рдХрд░рд╛." рдПрдХрджрд╛ рд╕реЗрдЯ рдХрд░рд╛, рдХрд╛рдпрдо рдиреАрдЯрдиреЗрдЯрдХреЗ.

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

flowchart LR
    tag["ЁЯП╖я╕П full-address label<br/>docker tag hello-school:v1<br/>ACCOUNT.dkr.ecr.REGIONтАж/hello-school:v1"]
    subgraph ecr["ЁЯПж ECR locker"]
        v3["ЁЯУж v3 - newest"]
        v2["ЁЯУж v2"]
        old["ЁЯУж v-oldтАж expired ЁЯз╣"]
    end
    eks["тШ╕я╕П EKS deployment<br/>image: ACCOUNT.dkrтАж/hello-school:v3"]
    jan["ЁЯз╣ lifecycle policy<br/>keep newest 10"]
    tag -->|"1 docker push"| ecr
    ecr -->|"2 pulled at deploy"| eks
    jan -.->|"3 tidies automatically"| old

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

ЁЯза Tag рд╡рд┐рд░реБрджреНрдз digest тАФ рдЖрдгрд┐ lifecycle policy рдЪреЗ рдПрдХ рдЙрджрд╛рд╣рд░рдг

tag     =  human-friendly name        my-app:v42        (mutable тАФ can be re-pointed)
digest  =  content identity           sha256:abc123тАж    (immutable тАФ the exact bytes)

my-app:v42  тФАтФАresolves today toтФАтФАтЦ╢  sha256:abc123тАж

Production deployments рдЕрдиреЗрдХрджрд╛ digest pin рдХрд░рддрд╛рдд (рдХрд┐рдВрд╡рд╛ immutable tags рд╡рд╛рдкрд░рддрд╛рдд) рдХрд╛рд░рдг рддреБрдореНрд╣реА test рдХреЗрд▓реНрдпрд╛рдирдВрддрд░ tag рд╡реЗрдЧрд│реНрдпрд╛ content рдХрдбреЗ рд╣рд▓рд╡рд▓рд╛ рдЬрд╛рдК рд╢рдХрддреЛ; digest рдирд╛рд╣реА. рдореНрд╣рдгреВрдирдЪ Kubernetes image: repo@sha256:тАж рд╕реНрд╡реАрдХрд╛рд░рддреЗ.

ECR рдордзреНрдпреЗ default рд╕рдлрд╛рдИ рдХрд░реНрдордЪрд╛рд░реА рдирд╛рд╣реА. Lifecycle policy рддреБрдореНрд╣реА рд▓рд┐рд╣рд╛рдпрдЪреА рдЕрд╕рддреЗ тАФ рдЙрджрд╛рд╣рд░рдгрд╛рд░реНрде: "рд╕рд░реНрд╡рд╛рдд рдирд╡реНрдпрд╛ 10 tagged images рдареЗрд╡рд╛; untagged images 7 рджрд┐рд╡рд╕рд╛рдВрдирдВрддрд░ expire рдХрд░рд╛." рддреБрдордЪреНрдпрд╛ rollback рдЪреНрдпрд╛ рдЧрд░рдЬрд╛рдВрдирд╛ рдЬреБрд│рдгрд╛рд░реЗ рдЖрдХрдбреЗ рдирд┐рд╡рдбрд╛.

ЁЯдФ рдХрд╛

рд╣рд╛ рдзрдбрд╛ рдореНрд╣рдгрдЬреЗрдЪ deploy рдЪрд╛ рдорд╛рд░реНрдЧ: рднрд╛рдЧ 1 рдиреЗ рдмрд╛рдВрдзрд▓реЗрд▓реЗ рд╕рдЧрд│реЗ рдЗрдереЗ cluster рд▓рд╛ рдЙрдкрд▓рдмреНрдз рд╣реЛрддреЗ. рдЖрдгрд┐ рд╕рдлрд╛рдИ рдХрд░реНрдордЪрд╛рд░реА рджрд┐рд╕рддреЛ рддреНрдпрд╛рдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд рдорд╣рддреНрддреНрд╡рд╛рдЪрд╛ рдЖрд╣реЗ: рдорд░реНрдпрд╛рджрд╛ рдирд╕рд▓реЗрд▓реНрдпрд╛ registries рд▓рд╛ рдЦрд░реЗ рдкреИрд╕реЗ рд▓рд╛рдЧрддрд╛рдд, scans рд╣рд│реВ рд╣реЛрддрд╛рдд, рдЖрдгрд┐ рдХреЛрдгрддреНрдпрд╛ images рдЦрд░реЛрдЦрд░ рдорд╣рддреНрддреНрд╡рд╛рдЪреНрдпрд╛ рдЖрд╣реЗрдд рддреЗ рд▓рдкрддреЗ. "рд╕рд░реНрд╡рд╛рдд рдирд╡реЗ 10 + рд╕реБрд░рдХреНрд╖рд┐рдд releases" рд╣рд╛ рдХрдВрдЯрд╛рд│рд╡рд╛рдгрд╛, рдкрдг рдпреЛрдЧреНрдп default рдЖрд╣реЗ.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛

REPO=$(aws ecr describe-repositories --repository-names hello-school \
  --query 'repositories[0].repositoryUri' --output text)     # your locker address

# 1) file a box: full-address label тЖТ push
docker tag hello-school:v1 "$REPO:v1"
docker push "$REPO:v1"                       # watch layers upload (then re-push: instant)

# 2) prove it's really there тАФ pull it back as a stranger would:
docker rmi "$REPO:v1"
docker pull "$REPO:v1" && echo "round trip complete ЁЯОЙ"

# 3) test IMMUTABLE tags (lesson 10's promise):
docker push "$REPO:v1" 2>&1 | tail -1        # rejected? no тАФ identical bytes are fine.
# now change the app, rebuild, and try to REUSE v1:
echo "// changed" >> app/server.js && docker build -t "$REPO:v1" app/ && git checkout app/server.js
docker push "$REPO:v1" 2>&1 | tail -1        # тЭМ "tag invalid: The image tag 'v1' already exists"

# 4) read the janitor's contract:
aws ecr get-lifecycle-policy --repository-name hello-school --query lifecyclePolicyText --output text

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

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

рддреБрдореНрд╣реА рдЖрддреНрддрд╛ tag тЖТ login тЖТ push рд╣рд╛рддрд╛рдиреЗ рдХреЗрд▓реЗ. рд╢реЗрд╡рдЯрдЪрд╛ рдзрдбрд╛ рд╣реЗ рд╕рдВрдкреВрд░реНрдг рдХрд╛рдо рдПрдХрд╛ robot рдХрдбреЗ рд╕реЛрдкрд╡рддреЛ тАФ рдЖрдгрд┐ рдкреБрдврдЪреНрдпрд╛ рджреЛрди рдХреЛрд░реНрд╕рдХрдбреЗ baton рджреЗрддреЛ.

git checkout lesson-12-ci-to-cloud

ЁЯз╣ Lesson 11 тАФ Push, pull & lifecycle: filing boxes and the janitor

ЁЯУН You are here: Lesson 11 of 12 ┬╖ Previous: lesson-10-ecr-setup ┬╖ Next: lesson-12-ci-to-cloud


ЁЯУж What's in this branch

Lessons 01тАУ10, plus: the daily ECR workflow тАФ tag with the full address, push, pull тАФ and the lifecycle policy that stops your locker from filling up with ancient lunches. Real file:

ЁЯзТ Explain like I'm 5

Filing a box at the bank has one rule people always trip on: the label must carry the FULL address ЁЯП╖я╕П. The bank won't accept a box labeled just hello-school:v1 тАФ which bank? which branch? which locker? The label must say:

123456789012.dkr.ecr.ap-south-1.amazonaws.com/hello-school:v1 (bank ┬╖ branch ┬╖ locker ┬╖ box name)

That's what docker tag does тАФ it doesn't copy anything, it just writes a second, fully-addressed label on the same box. Then docker push reads the label and knows exactly where to deliver.

And the janitor ЁЯз╣: every push adds a box, forever. A year of daily deploys = 365 boxes of mostly-mummified lunch, and the bank charges by the shelf-centimeter. The lifecycle policy is standing instructions to the janitor: "keep the newest 10 boxes; quietly expire the rest." Set once, tidy forever.

ЁЯЧ║я╕П Diagram

flowchart LR
    tag["ЁЯП╖я╕П full-address label<br/>docker tag hello-school:v1<br/>ACCOUNT.dkr.ecr.REGIONтАж/hello-school:v1"]
    subgraph ecr["ЁЯПж ECR locker"]
        v3["ЁЯУж v3 - newest"]
        v2["ЁЯУж v2"]
        old["ЁЯУж v-oldтАж expired ЁЯз╣"]
    end
    eks["тШ╕я╕П EKS deployment<br/>image: ACCOUNT.dkrтАж/hello-school:v3"]
    jan["ЁЯз╣ lifecycle policy<br/>keep newest 10"]
    tag -->|"1 docker push"| ecr
    ecr -->|"2 pulled at deploy"| eks
    jan -.->|"3 tidies automatically"| old

тЭУ What

ЁЯза Tag vs digest тАФ and an example lifecycle policy

tag     =  human-friendly name        my-app:v42        (mutable тАФ can be re-pointed)
digest  =  content identity           sha256:abc123тАж    (immutable тАФ the exact bytes)

my-app:v42  тФАтФАresolves today toтФАтФАтЦ╢  sha256:abc123тАж

Production deployments often pin the digest (or use immutable tags) because a tag can be moved to different content after you tested it; a digest cannot. Kubernetes accepts image: repo@sha256:тАж for exactly this.

ECR has no default janitor. A lifecycle policy is something you write тАФ for example: "keep the newest 10 tagged images; expire untagged images after 7 days." Pick numbers that match your rollback needs.

ЁЯдФ Why

This lesson IS the deploy path: everything Part 1 built becomes available to the cluster here. And the janitor matters more than it looks: unbounded registries cost real money, slow scans, and hide which images actually matter. "Newest 10 + protected releases" is the boring, correct default.

ЁЯзк Try it

REPO=$(aws ecr describe-repositories --repository-names hello-school \
  --query 'repositories[0].repositoryUri' --output text)     # your locker address

# 1) file a box: full-address label тЖТ push
docker tag hello-school:v1 "$REPO:v1"
docker push "$REPO:v1"                       # watch layers upload (then re-push: instant)

# 2) prove it's really there тАФ pull it back as a stranger would:
docker rmi "$REPO:v1"
docker pull "$REPO:v1" && echo "round trip complete ЁЯОЙ"

# 3) test IMMUTABLE tags (lesson 10's promise):
docker push "$REPO:v1" 2>&1 | tail -1        # rejected? no тАФ identical bytes are fine.
# now change the app, rebuild, and try to REUSE v1:
echo "// changed" >> app/server.js && docker build -t "$REPO:v1" app/ && git checkout app/server.js
docker push "$REPO:v1" 2>&1 | tail -1        # тЭМ "tag invalid: The image tag 'v1' already exists"

# 4) read the janitor's contract:
aws ecr get-lifecycle-policy --repository-name hello-school --query lifecyclePolicyText --output text

тЪая╕П Common mistakes

тПня╕П Next

You just did tag тЖТ login тЖТ push by hand. The final lesson hands the whole routine to a robot тАФ and passes the baton to the next two courses.

git checkout lesson-12-ci-to-cloud
тЖР Previousecr setupNext тЖТci to cloud

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