Container-native without k8s:
PHP in ECS on AWS
PHP UK Conference 2022
Ian Littman (CTO @ Covie) / @iansltx
Follow along at ian.im/ecsuk22
Warning: AWS Console Interaction Ahead
Why ECS?
- We have everything in Docker locally (docker-compose)
- Had decided to use AWS for our infrastructure
- Wanted to minimize cost and operational overhead (so k8s was out)
- Didn't want to use the other 33+ ways of running containers in AWS
In the vein of keeping things simple, we're using Fargate, both for Covie and here.
Here's what we need, starting from scratch
- Domain + Route53 Zone
- Security group for ALB
- ECR repository (push your app image here)
- ECS Cluster (Networking Only)
- ECS Task Definition (incl. container definition)
- Target Group (IP)
- Application Load Balancer (pointed at #6 target group)
- DNS for #7 (A alias record)
- ECS Service (using #5, #7)
Let's do this.
Step 1: It's always DNS
- Acquire a domain
- Set up a hosted zone in Route53 for that domain
- Point NS records at AWS
- Did this ahead of time to ensure things resolve (this is why it's step 1)
- You want Route53 running your DNS so ALB alias recrods work right
Step 2: Security Groups
- Web -> load balancer (anything on ports 80/443)
- Load balancer -> application (load balancer SG to app port 80)
- We don't have e.g. SSH here, as we won't be logging into our app tier ever.
- Need one rule per port per IP version
- We'll create the load balancer to application SG later
Step 3: ECR Repository
- Add repository
- (optional) turn on image scanning (in Registry settings)
- Push code (you'll need AWS CLI + appropriate creds locally)
Show me the code!
FROM php:8.1.2-cli-alpine3.15 WORKDIR /var/app RUN echo '<?= "<h1>Hello " . strip_tags($_GET["to"] ?? $_ENV["to"] ?? "World") . "!</h1>" ?>' > index.php EXPOSE 80 CMD php -d variables_order=EPGCS -S 0.0.0.0:80
Pushing the code
aws ecr get-login-password --region REGION \
| docker login --username AWS --password-stdin \
ACCOUNT_ID.dkr.ecr.REGION.amazonaws.com
docker build -t TAG . docker tag TAG:latest \ ACCOUNT_ID.dkr.ecr.REGION.amazonaws.com/TAG:latest docker push ACCOUNT_ID.dkr.ecr.REGION.amazonaws.com/TAG:latest
Step 4: ECS Cluster
- Networking Only (since we're only using Fargate)
- You may want to turn on Container Insights (costs extra $$ though)
- You may want to add capacity providers (e.g. Fargate Spot)
Step 5: ECS Task Definition
- These are versioned
- In the old console, there are tons of irrelevant options
- In the new console, things randomly don't work and you can't tell why
Task Definitions: A note on ECS IAM roles
- Task: while the container is running
- Pulling files from S3
- Sending emails via SES
- Task Execution: while the container is being set up
- Image pulls
- Environment variables from Secrets Manager
- ecsTaskExecutionRole has the policy you need for image pulls
Task definitions: CPU
- Minimum of 2 GB of RAM per vCPU (though you can do fractional vCPUs)
- vCPU shares are fixed; no burst!
- You have to pick an architecture (x86, Arm) per task definition version
- You can't pick Arm in the console UI
- You can, but don't have to, specify CPU share within a "task" (think VM)
Task definitions: Container Definitions
- Image name fmt: ACCT_ID.dkr.ecr.REGION.amazonaws.com/REPO:TAG
- Port mappings in Fargate are directly exposed from the container
- No e.g. mapping from 8080 to 80
- Each container in a task has to expose a unique port
- Containers within a task can access others in that task, if exposed, at localhost:[exposed port]
- Environment variables
- Can be from AWS Secrets Manager, via ValueFrom
- Secret ARN format: arn:aws:secretsmanager:REGION:ACCT_ID:secret:NAME-SUFFIX:FIELD::
Step 6: Target Group
- This is what you'll attach your ALB to
- Choose an IP as a target...any allowed IP in your VPC
Step 7: Application Load Balancer
- For HTTPS, generate a cert via ACM (easy to do DNS verification via R53)
- Forward to the Target Group you set up in Step 6
- Add a listener to redirect HTTP to HTTPS
Step 8: It's DNS Again
Step 9: ECS Service
- Create your LB -> app security group here
- Pick your ALB from the list...
- ...and use the target group you set up earlier...
- You can set up autoscaling here too!
Need job processing? Use scheduled tasks
- Cron schedule expression: e.g. cron(2 8 * * ? *)
- The ? in the cron expression blanks out day-of-month or day-of-week
- If overriding a command, separate arguments with commas.
THINGS YOU MAY WANT IN PRODUCTION
- Data stores (we use Aurora)
- IAM role precision
- Non-default VPC
- GuardDuty, etc.
- Infrastructure as Code
Thanks! Questions?
- ian.im/ecsuk22 - these slides
- twitter.com/iansltx - me, online
Container-Native Without k8s: PHP in ECS on AWS - PHP UK 2022
By Ian Littman
Container-Native Without k8s: PHP in ECS on AWS - PHP UK 2022
When building Covie, I got to pick our tech stack, including where and how to run it. The choice was containerized on ECS with AWS, starting on Fargate…and so far, so good. We’ll walk through how to set this stack up, with some tips and tricks along the way.
- 802