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

  1. Domain + Route53 Zone
  2. Security group for ALB
  3. ECR repository (push your app image here)
  4. ECS Cluster (Networking Only)
  5. ECS Task Definition (incl. container definition)
  6. Target Group (IP)
  7. Application Load Balancer (pointed at #6 target group)
  8. DNS for #7 (A alias record)
  9. ECS Service (using #5, #7)

Let's do this.

Step 1: It's always DNS

  1. Acquire a domain
  2. Set up a hosted zone in Route53 for that domain
  3. 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

  1. Web -> load balancer (anything on ports 80/443)
  2. 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

  1. Add repository
  2. (optional) turn on image scanning (in Registry settings)
  3. 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

THINGS YOU MAY WANT IN PRODUCTION

  • Data stores (we use Aurora)
  • IAM role precision
  • Non-default VPC
  • GuardDuty, etc.
  • Infrastructure as Code

Thanks! Questions?

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.

  • 680