For the day job, I maintain four custom PHP apps in addition to several Drupal sites. Up until a couples months ago, each of the apps was hosted on-premise in LAMP virtual machines that our IT department maintains. With PHP 5.6 end-of-life at the end of 2018, the IT department decided it didn’t have the resources to maintain and upgrade hardware, meaning they couldn’t support PHP apps internally anymore, so they offered up AWS as an alternative. All I had to do was update the apps to work on PHP 7, get the apps containerized and running on Docker, migrate the filesystem access to S3 buckets, migrate the databases to RDS, migrate email code to use SendGrid, and migrate authentication to use SAML. Yep, that’s all. I won’t go through the whole process, but maybe highlight some wins and pain-points.
One of the major benefits of Docker is running services in isolation. So it’s possible to have one container running PHP 5.6 and another PHP 7.2 and another PHP 7.1. Likewise with MySql or whatever other service, you don’t have to fret about running multiple versions, or versions different from production. In the past I used VMs, usually with Vagrant, or just installed a development environment directly on the host machine, but both of those options basically involve building and maintaining servers. I’ve done that enough to not want to do it anymore. With docker I can create a Dockerfile that says “FROM php:7.2-apache” plus a couple of other commands to copy code into the image, and I’m golden. In the end, I settled on using docker-compose to create three containers: app, database, and tests. Something like this:
version: '3.5' services: web: build: context: . dockerfile: Dockerfile container_name: app-1 env_file: .env.dev image: app-1:latest db: build: context: . dockerfile: Dockerfile-mysql container_name: app-1-mysql environment: MYSQL_ROOT_PASSWORD: test image: app-1-mysql:latest tests: build: context: . dockerfile: Dockerfile-tests container_name: app-1-tests env_file: .env.dev image: app-1-tests:latest networks: default: name: app-1-network
With this, I can run
docker-compose build && docker-compose up, and I have a full development environment. You can also specify multiple docker-compose files, so if you want to do something only when developing, you can do something like
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up, where the docker-compose.dev.yml looks like this:
version: '3.5' services: web: volumes: - ./src:/var/www/src/ - ./public:/var/www/html/ ports: - "8008:80" db: ports: - "3309:3306"
So now I have my code mounted, a web server accessible on the host at port 8008, and a database accessible on the host at port 3309, all with just a few text files.
So now that the apps are containerized, we need to get them running on PHP 7, and get them working with third-party resources. Running apps on containers in AWS Fargate means we don’t have native access to persistent storage. You can use something like EBS, but it seemed easier to just modify the apps to read and write to S3 buckets. The containers also don’t have an email server, so we need to write some code to use a third-party email service.
Next, we’ll need to deploy the apps to Amazon. We’ll use a CI/CD pipeline to that. Of course we also need to setup and manage the infrastructure on Amazon, i.e. Fargate, RDS, S3, VPCs, etc.
I’ll write about each of those in upcoming installments.