ЁЯПл The SchoolтА║ЁЯЦея╕П EC2тА║ЁЯЦ╝я╕П рдзрдбрд╛ 03 тАФ AMIs рдЖрдгрд┐ launch templates: рдбреЗрд╕реНрдХрдЪрд╛ рд╕рд╛рдЪрд╛ рдЖрдгрд┐ recipe card
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯЦ╝я╕П рдзрдбрд╛ 03 тАФ AMIs рдЖрдгрд┐ launch templates: рдбреЗрд╕реНрдХрдЪрд╛ рд╕рд╛рдЪрд╛ рдЖрдгрд┐ recipe card

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 03 ┬╖ рдорд╛рдЧреЗ: lesson-02-instance-types ┬╖ рдкреБрдвреЗ: lesson-04-storage


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

рдзрдбреЗ 01тАУ02, рдЖрдгрд┐ instance рдХрд╢рд╛рдкрд╛рд╕реВрди рдмрдирддреЛ рддреЗ: AMI (рдбреЗрд╕реНрдХрдЪрд╛ рд╕рд╛рдЪрд╛), launch template (AMI, type, disk, badge рдЖрдгрд┐ рдкрд╛рд╣реБрдгреНрдпрд╛рдВрдЪреА рдпрд╛рджреА рд▓рд┐рд╣рд┐рд▓реЗрд▓реЗ recipe card), рдЖрдгрд┐ user data тАФ рдкрд╣рд┐рд▓реНрдпрд╛ boot рдЪреА script, ec2/templates/user-data.sh. Recipe card рд╕реНрд╡рддрдГ ec2/templates/web.json рдЖрд╣реЗ.

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

рдЕрднреНрдпрд╛рд╕рд┐рдХреЗрдд рдирд╡рд╛ рдбреЗрд╕реНрдХ рдЖрд▓рд╛ рдХреА рддреЛ рд╢реВрдиреНрдпрд╛рдкрд╛рд╕реВрди рддрдпрд╛рд░ рдХрд░рд╛рдпрд▓рд╛ рдХреЛрдгрд╛рд▓рд╛рдЪ рдЖрд╡рдбрдд рдирд╛рд╣реА: рджрд┐рд╡рд╛ рдмрд╕рд╡рд╛, stationery рдареЗрд╡рд╛, рднрд┐рдВрддреАрд╡рд░ рд╡реЗрд│рд╛рдкрддреНрд░рдХ рдЪрд┐рдХрдЯрд╡рд╛. рдореНрд╣рдгреВрди рдХрдВрдкрдиреА рдПрдХ рдбреЗрд╕реНрдХрдЪрд╛ рд╕рд╛рдЪрд╛ ЁЯЦ╝я╕П рдареЗрд╡рддреЗ тАФ рдЕрдЧрджреА рдлреЛрдЯреЛрд╕рд╛рд░рдЦрд╛ рдкрд░рд┐рдкреВрд░реНрдг, рдЖрдзреАрдЪ рддрдпрд╛рд░ рдХреЗрд▓реЗрд▓рд╛ рдбреЗрд╕реНрдХ. рдкреНрд░рддреНрдпреЗрдХ рдирд╡рд╛ рдбреЗрд╕реНрдХ рддреНрдпрд╛рдЪреА рдирдХреНрдХрд▓ рдХрд░реВрди рдмрдирддреЛ. рддреЛ рд╕рд╛рдЪрд╛ рдореНрд╣рдгрдЬреЗ AMI (Amazon Machine Image).

рдордЧ рднрд┐рдВрддреАрд╡рд░ рд▓рд╛рд╡рд▓реЗрд▓реЗ рдПрдХ recipe card ЁЯУЗ рдЕрд╕рддреЗ: "рдПрдХ t4g.small рдбреЗрд╕реНрдХ, ami-0abcтАж рд╕рд╛рдЪреНрдпрд╛рд╡рд░реВрди рдирдХреНрдХрд▓ рдХреЗрд▓реЗрд▓рд╛, 16 GB рдбреНрд░реЙрд╡рд░рд╕рд╣, рд╣рд╛ badge, рд╣реА рдкрд╛рд╣реБрдгреНрдпрд╛рдВрдЪреА рдпрд╛рджреА тАФ рдЖрдгрд┐ рддреЛ рдирд╡рд╛ рдЕрд╕рддрд╛рдирд╛ рдпрд╛ рддреАрди рдкрд╛рдпрд▒реНрдпрд╛ рдПрдХрджрд╛ рдЪрд╛рд▓рд╡рд╛". рддреЗ card рдореНрд╣рдгрдЬреЗ launch template. "рдпрд╛ рдкрд╛рдпрд▒реНрдпрд╛ рдПрдХрджрд╛ рдЪрд╛рд▓рд╡рд╛" рд╣рд╛ рднрд╛рдЧ рдореНрд╣рдгрдЬреЗ user data.

Card рдХрд╢рд╛рд╕рд╛рдареА? рдХрд╛рд░рдг рджрд╣рд╛рд╡рд╛ рдбреЗрд╕реНрдХ рдкрд╣рд┐рд▓реНрдпрд╛рд╕рд╛рд░рдЦрд╛рдЪ рд╣реБрдмреЗрд╣реВрдм рдЕрд╕рд▓рд╛ рдкрд╛рд╣рд┐рдЬреЗ. рдПрдЦрд╛рджрд╛ рдбреЗрд╕реНрдХ рдмрд┐рдШрдбрд▓рд╛ рддрд░ рддреБрдореНрд╣реА рддреЛ рдПрдХреЗрдХ screw рдХрд░реВрди рджреБрд░реБрд╕реНрдд рдХрд░рдд рдирд╛рд╣реА тАФ рддреЛ рдлреЗрдХреВрди рджреЗрдКрди card рд╡рд░реВрди рдирд╡рд╛ рдмрдирд╡рддрд╛.

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

flowchart LR
    ami["ЁЯЦ╝я╕П AMI ami-0abc1234example<br/>OS + software, arm64"]
    lt["ЁЯУЗ launch template web.json<br/>t4g.small ┬╖ 16 GB gp3 ┬╖ badge school-web ┬╖ sg-0web"]
    ud["ЁЯУЬ user-data.sh<br/>dnf install nginx ┬╖ write index.html ┬╖ enable nginx"]
    d1["ЁЯЦея╕П desk 1"]
    d2["ЁЯЦея╕П desk 2"]
    d3["ЁЯЦея╕П desk 3"]
    ami -->|"1 copied from"| lt
    ud -->|"2 runs once, as root, first boot"| lt
    lt -->|"3 launch"| d1
    lt --> d2
    lt --> d3
    same["тЬЕ every desk identical тАФ broken? replace, never repair manually"]
    d3 -.-> same

ЁЯЧ║я╕П рдХрд╛рдврд▓реЗрд▓реА рдЖрдХреГрддреА + рдПрдХ lab: https://school-edh.pages.dev/ec2/lesson-diagrams.html#l03

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

ЁЯдФ рдХрд╛

рдХрд╛рд░рдг рд╣рд╛рддрд╛рдиреЗ рддрдпрд╛рд░ рдХреЗрд▓реЗрд▓рд╛ server рдкреБрдиреНрд╣рд╛ рдХреЛрдгрд╛рд▓рд╛рдЪ рдмрдирд╡рддрд╛ рдпреЗрдд рдирд╛рд╣реА. Recipe card рдореБрд│реЗ рджрд╣рд╛рд╡рд╛ рдбреЗрд╕реНрдХ рдкрд╣рд┐рд▓реНрдпрд╛рд╕рд╛рд░рдЦрд╛рдЪ рдмрдирддреЛ, Auto Scaling рддреБрдордЪреНрдпрд╛рд╢рд┐рд╡рд╛рдп рд░рд╛рддреНрд░реА 3 рд╡рд╛рдЬрддрд╛ рдбреЗрд╕реНрдХ рдмрдирд╡реВ рд╢рдХрддреЗ, рдЖрдгрд┐ "рдмрд┐рдШрдбрд▓реЗрд▓рд╛ рдбреЗрд╕реНрдХ рджреБрд░реБрд╕реНрдд рдХрд░рд╛" рдЪреЗ рд░реВрдкрд╛рдВрддрд░ "рддреЛ рдмрджрд▓рд╛" рдордзреНрдпреЗ рд╣реЛрддреЗ тАФ рдзрдбрд╛ 09 рдЖрдгрд┐ рдзрдбрд╛ 12 рдорд╛рдЧрдЪреА рд╣реАрдЪ рд╕рд╡рдп.

ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)

ec2/demo.py рдордзрд▓реЗ launch() ec2/templates/web.json рдЙрдШрдбрддреЗ тАФ рдЬреА AWS CLI рд▓рд╛ рджрд┐рд▓реНрдпрд╛ рдЬрд╛рдгрд╛рд▒реНрдпрд╛ --launch-template-data рд╕рд╛рд░рдЦреАрдЪ рд░рдЪрд▓реЗрд▓реА рдЖрд╣реЗ тАФ рдореБрдЦреНрдп fields рдЫрд╛рдкрддреЗ, рдордЧ рдкрд╣рд┐рд▓реНрдпрд╛ boot рдЪреА script ec2/templates/user-data.sh рдЫрд╛рдкрддреЗ. ImageId рд╣рд╛ placeholder рдЖрд╣реЗ (ami-0abc1234example) рдЖрдгрд┐ UserData рдордзреНрдпреЗ (base64 of user-data.sh) рд▓рд┐рд╣рд┐рд▓реЗрд▓реЗ рдЖрд╣реЗ: рдЦрд▒реНрдпрд╛ account рд╡рд░ рддреБрдореНрд╣реА рджреЛрдиреНрд╣реА рдмрджрд▓рддрд╛.

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

python3 ec2/demo.py launch
python3 - <<'EOF'
import base64, json
t = json.load(open("ec2/templates/web.json"))
print("disk:", t["BlockDeviceMappings"][0]["Ebs"])
print("metadata:", t["MetadataOptions"])
print("tags:", t["TagSpecifications"][0]["Tags"])
# a launch template wants UserData base64-encoded тАФ this is what replaces the placeholder
ud = base64.b64encode(open("ec2/templates/user-data.sh", "rb").read()).decode()
print("UserData:", ud[:40] + "тАж", f"({len(ud)} characters)")
EOF

рдЦрд▒реНрдпрд╛ account рд╡рд░ (AWS credentials рд▓рд╛рдЧрддрд╛рдд; run-instances рдиреЗ billing рд╕реБрд░реВ рд╣реЛрддреЗ тАФ рдирдВрддрд░ terminate рдХрд░рд╛). рдЖрдзреА web.json рдЪреНрдпрд╛ рдПрдХрд╛ copy рдордзреНрдпреЗ рдЦрд░рд╛ arm64 AMI ID, рдЦрд░рд╛ security group ID рдЖрдгрд┐ base64 user data рдЯрд╛рдХрд╛, рдЖрдгрд┐ school-web instance profile рдмрдирд╡рд╛ (рдзрдбрд╛ 07) тАФ рдХрд┐рдВрд╡рд╛ рд╕рдзреНрдпрд╛ рддреА рдУрд│ рдХрд╛рдвреВрди рдЯрд╛рдХрд╛:

aws ssm get-parameter \
    --name /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64 \
    --query Parameter.Value --output text
aws ec2 create-launch-template --launch-template-name school-web \
    --launch-template-data file://my-web.json
aws ec2 run-instances --launch-template 'LaunchTemplateName=school-web,Version=$Latest' --count 1
aws ec2 terminate-instances --instance-ids i-0123456789abcdef0

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

launch рдЫрд╛рдкрддреЗ ImageId "ami-0abc1234example", InstanceType "t4g.small", IamInstanceProfile {"Name": "school-web"}, SecurityGroupIds ["sg-0web"], рдордЧ UserData (runs once, as root, on first boot): рдЦрд╛рд▓реА script рдЪреНрдпрд╛ рддреАрди рдУрд│реА тАФ dnf install -y nginx, index.html рдордзреНрдпреЗ рдЬрд╛рдгрд╛рд░рд╛ echo, рдЖрдгрд┐ systemctl enable --now nginx. рддреБрдордЪрд╛ snippet disk рдЫрд╛рдкрддреЛ ('VolumeSize': 16, 'VolumeType': 'gp3', 'Encrypted': True, 'DeleteOnTermination': True), metadata options ('HttpTokens': 'required', 'HttpPutResponseHopLimit': 1 тАФ рдзрдбрд╛ 07 рддреНрдпрд╛рдВрдЪреЗ рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг рджреЗрддреЛ), tag 'Key': 'team', 'Value': 'maths', рдЖрдгрд┐ UserData: IyEvYmluL2Jhc2gKIyBSdW5zIE9OQ0UsIGFzIHJvтАж (328 characters).

ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ

рдПрдХ recipe card рдЖрдгрд┐ рдПрдХ рд╕рд╛рдЪрд╛ рдбреЗрд╕реНрдХрдЪреЗ рдкреВрд░реНрдг рд╡рд░реНрдгрди рдХрд░рддрд╛рдд тАФ рддреБрдореНрд╣реА рддреНрдпрд╛рдЪреА рдкреНрд░рддреНрдпреЗрдХ рдУрд│ рд╡рд╛рдЪрд▓реА, рдкрд╣рд┐рд▓реНрдпрд╛ boot рд▓рд╛ рдПрдХрджрд╛ рдЪрд╛рд▓рдгрд╛рд▒реНрдпрд╛ script рд╕рд╣, рдЖрдгрд┐ рдЦрд▒реНрдпрд╛ launch template рд▓рд╛ рд▓рд╛рдЧрдгрд╛рд░рд╛ рдиреЗрдордХрд╛ base64 рддрдпрд╛рд░ рдХреЗрд▓рд╛.

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

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: Auto Scaling, instance refresh рдЖрдгрд┐ disaster recovery рд╣реЗ рд╕рдЧрд│реЗ launch template рд╣реЗрдЪ рдбреЗрд╕реНрдХрдмрджреНрджрд▓рдЪреЗ рдкреВрд░реНрдг рд╕рддреНрдп рдЖрд╣реЗ рдЕрд╕реЗ рдЧреГрд╣реАрдд рдзрд░рддрд╛рдд. Teams рддреЗ code рдордзреНрдпреЗ рдареЗрд╡рддрд╛рдд (CloudFormation, Terraform, CDK), code рд╕рд╛рд░рдЦреЗрдЪ review рдХрд░рддрд╛рдд, рдЖрдгрд┐ "рдлрдХреНрдд рдПрдХ рдЧреЛрд╖реНрдЯ рджреБрд░реБрд╕реНрдд рдХрд░рд╛рдпрд▓рд╛" рдХрдзреАрдЪ login рдХрд░рдд рдирд╛рд╣реАрдд.

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

рдбреЗрд╕реНрдХрд▓рд╛ рдПрдХ рдбреНрд░реЙрд╡рд░, рдПрдХ рдЦрд░рдбрд╡рд╣реА рдЖрдгрд┐ hall рдЪреНрдпрд╛ рдЯреЛрдХрд╛рд▓рд╛ рдПрдХ photocopier рдЖрд╣реЗ тАФ рдЖрдгрд┐ рддреЗ рдЕрдЧрджреА рд╡реЗрдЧрд╡реЗрдЧрд│реНрдпрд╛ рдЧреЛрд╖реНрдЯреАрдВрдирдВрддрд░ рдЯрд┐рдХрддрд╛рдд. Storage: EBS рдЖрдгрд┐ snapshots.

git checkout lesson-04-storage

ЁЯЦ╝я╕П Lesson 03 тАФ AMIs & launch templates: the desk template and the recipe card

ЁЯУН You are here: Lesson 03 of 12 ┬╖ Previous: lesson-02-instance-types ┬╖ Next: lesson-04-storage


ЁЯУж What's in this branch

Lessons 01тАУ02, plus what an instance is built from: the AMI (the desk template), the launch template (the recipe card that names the AMI, type, disk, badge and guest list), and user data тАФ the first-boot script in ec2/templates/user-data.sh. The recipe card itself is ec2/templates/web.json.

ЁЯзТ Explain like I'm 5

When the study hall gets a new desk, nobody wants to set it up from nothing: screw on the lamp, put the stationery in, stick the timetable on the wall. So the company keeps a desk template ЁЯЦ╝я╕П тАФ a photo-perfect desk, already set up. Every new desk is copied from it. That template is an AMI (Amazon Machine Image).

Then there is the recipe card ЁЯУЗ pinned to the wall: "a t4g.small desk, copied from template ami-0abcтАж, with a 16 GB drawer, this badge, this guest list тАФ and when it is new, run these three steps once". That card is a launch template. The "run these steps once" part is user data.

Why a card? Because the tenth desk must be identical to the first. If a desk breaks, you do not repair it one screw at a time тАФ you throw it out and build a new one from the card.

ЁЯЧ║я╕П Diagram

flowchart LR
    ami["ЁЯЦ╝я╕П AMI ami-0abc1234example<br/>OS + software, arm64"]
    lt["ЁЯУЗ launch template web.json<br/>t4g.small ┬╖ 16 GB gp3 ┬╖ badge school-web ┬╖ sg-0web"]
    ud["ЁЯУЬ user-data.sh<br/>dnf install nginx ┬╖ write index.html ┬╖ enable nginx"]
    d1["ЁЯЦея╕П desk 1"]
    d2["ЁЯЦея╕П desk 2"]
    d3["ЁЯЦея╕П desk 3"]
    ami -->|"1 copied from"| lt
    ud -->|"2 runs once, as root, first boot"| lt
    lt -->|"3 launch"| d1
    lt --> d2
    lt --> d3
    same["тЬЕ every desk identical тАФ broken? replace, never repair manually"]
    d3 -.-> same

ЁЯЧ║я╕П Drawn version + a lab: https://school-edh.pages.dev/ec2/lesson-diagrams.html#l03

тЭУ What

ЁЯдФ Why

Because a server set up manually is a server nobody can build again. The recipe card makes the tenth desk the same as the first, lets Auto Scaling build desks at 3 a.m. without you, and turns "fix the broken desk" into "replace it" тАФ the habit behind lesson 09 and lesson 12.

ЁЯФз How (in this repo)

launch() in ec2/demo.py opens ec2/templates/web.json тАФ shaped exactly like the --launch-template-data you give the AWS CLI тАФ prints the key fields, then prints the first-boot script ec2/templates/user-data.sh. The ImageId is a placeholder (ami-0abc1234example) and UserData says (base64 of user-data.sh): on a real account you replace both.

ЁЯзк Try it

python3 ec2/demo.py launch
python3 - <<'EOF'
import base64, json
t = json.load(open("ec2/templates/web.json"))
print("disk:", t["BlockDeviceMappings"][0]["Ebs"])
print("metadata:", t["MetadataOptions"])
print("tags:", t["TagSpecifications"][0]["Tags"])
# a launch template wants UserData base64-encoded тАФ this is what replaces the placeholder
ud = base64.b64encode(open("ec2/templates/user-data.sh", "rb").read()).decode()
print("UserData:", ud[:40] + "тАж", f"({len(ud)} characters)")
EOF

On a real account (needs AWS credentials; run-instances starts billing тАФ terminate it afterwards). First put a real arm64 AMI ID, a real security group ID and the base64 user data into a copy of web.json, and create the school-web instance profile (lesson 07) тАФ or delete that line for now:

aws ssm get-parameter \
    --name /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64 \
    --query Parameter.Value --output text
aws ec2 create-launch-template --launch-template-name school-web \
    --launch-template-data file://my-web.json
aws ec2 run-instances --launch-template 'LaunchTemplateName=school-web,Version=$Latest' --count 1
aws ec2 terminate-instances --instance-ids i-0123456789abcdef0

тЬЕ Verify тАФ what you should see

launch prints ImageId "ami-0abc1234example", InstanceType "t4g.small", IamInstanceProfile {"Name": "school-web"}, SecurityGroupIds ["sg-0web"], then the three script lines under UserData (runs once, as root, on first boot): тАФ dnf install -y nginx, the echo into index.html, and systemctl enable --now nginx. Your snippet prints the disk ('VolumeSize': 16, 'VolumeType': 'gp3', 'Encrypted': True, 'DeleteOnTermination': True), the metadata options ('HttpTokens': 'required', 'HttpPutResponseHopLimit': 1 тАФ lesson 07 explains them), the tag 'Key': 'team', 'Value': 'maths', and UserData: IyEvYmluL2Jhc2gKIyBSdW5zIE9OQ0UsIGFzIHJvтАж (328 characters).

ЁЯПБ What you just proved

A desk is fully described by a recipe card and a template тАФ you read every line of it, including the script that runs once on first boot, and produced the exact base64 a real launch template needs.

тЪая╕П Common mistakes

ЁЯПн Why this matters in production: Auto Scaling, instance refresh and disaster recovery all assume the launch template is the complete truth about a desk. Teams keep it in code (CloudFormation, Terraform, CDK), review it like code, and never log in to "just fix one thing".

тПня╕П Next

The desk has a drawer, a scratch pad and a photocopier down the hall тАФ and they survive very different things. Storage: EBS and snapshots.

git checkout lesson-04-storage
тЖР Previousinstance typesNext тЖТstorage

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