Introduction
In Part 2, we covered the implementation of chat functionality with LiveView, LiveComponent, PubSub, and Channels. In this final article, we’ll focus on compiling the application locally and deploying it to AWS EC2.
Create Dockerfile
A Dockerfile
outlines a series of commands for Docker to build the application environment. By using a Dockerfile, we can create a consistent image of a test environment, which can be effortlessly and reliably recreated without the need for manual setup and configuration for each test run.
This is the sample Dockerfile .
ARG ELIXIR_VERSION=1.16.3
ARG OTP_VERSION=26.1.2
ARG DEBIAN_VERSION=bullseye-20240612-slim
ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}"
ARG RUNNER_IMAGE="debian:${DEBIAN_VERSION}"
FROM --platform=linux/amd64 ${BUILDER_IMAGE} as builder
# install build dependencies
RUN apt-get update -y && apt-get install -y build-essential git \
&& apt-get clean && rm -f /var/lib/apt/lists/*_*
# prepare build dir
WORKDIR /app
...
Run application by docker-compose
For ease of local testing, create a prod.env
file with the following content:
export SECRET_KEY_BASE=<key>
export HOST=chat.vn
export PHX_HOST=chat.vn
export PHX_HTTP_PORT=8080
export PHX_HTTPS_PORT=443
export MIX_ENV=prod
export DATABASE_FILE="/data/chat_service_dev.db"
export DOCKER_DEFAULT_PLATFORM=linux/amd64
Replace <key>
with own secret key by running the command mix phx.gen.secret
. This prod.env
file will automatically set the necessary environment variables for configuring our application.
Next, Docker Compose will help us run the application locally. Create a docker-compose.yml
file in our project root with the following content:
version: '3'
services:
elixir:
build:
network: host
context: .
dockerfile: Dockerfile
env_file: prod.env
environment:
- DATABASE_FILE=/data/chat_service_dev.db
platform: linux/amd64
ports:
- "4433:443"
- "8080:8080"
container_name: chat_service
volumes:
- ./data:/data
- ./priv/cert:/cert
In this setup, Docker Compose will use the prod.env
file to export the required environment variables into the running container.
To start the application, run docker-compose up
or docker-compose up -d
to run it in the background.
Once everything is up and running, we can open our browser and navigate to http://localhost:8080/chat_room?user_id=john&channel_id=game_1
to see the application in action.
After we will save image we just created to tar file:
docker save -o chat_service.tar <image_id>
and we need to run docker image ls
to get image_id
.
Deploy Docker image to Amazon EC2
First, in AWS, navigate to the EC2 dashboard and launch an instance by visiting this link (https://us-east-1.console.aws.amazon.com/ec2/home?region=us-east-1#LaunchInstances).
Select Debian 12 with a 64-bit (x86) architecture, which is eligible for the free tier. This option is sufficient for our needs as our application doesn’t require a high-performance machine.
For the instance type, choose t2.micro. When setting up the Key Pair for login, create a new one and ensure we save it to our local machine. For all other settings, we can leave them as default.
Navigate to the EC2 instance dashboard to view our instances.
In the Security Groups section, we'll see that the SSH port is pre-configured by default. Since we’ll be hosting a web app on this instance, we need to add another configuration. By default, Phoenix’s web server runs on port 8080. To allow traffic on this port, go to the Security tab and add a new Inbound rule for port 8080.
Finally, we can start our EC2 instances by command:
aws ec2 start-instances --instance-ids <instance_id>
.
Remember install aws command and get instance-ids name from dashboard.
Wait few seconds, check instance state in EC2 dashboard, we can see it will change status from Stopped -> Pending -> Running,
Locate your private key file. The key used to launch this instance is .pem. Run this command, if necessary, to ensure your key is not publicly viewable: chmod 400 "<name>.pem"
.
Then we will connect to the EC2 machine by command using its Public DNS and host name is admin:
ssh -i "<name>.pem" admin@<Public IPv4 DNS>
In EC2 machine, we also need to create prod.env
and docker_compose.yml
file:
prod.env:
SECRET_KEY_BASE="<key>"
HOST=chat.vn
PHX_HOST=chat.vn
PHX_HTTP_PORT=8080
PHX_HTTPS_PORT=443
MIX_ENV=prod
DATABASE_FILE="/data/chat_service_dev.db"
docker_compose.yml:
version: '3'
services:
elixir:
image: <image_id>
env_file: prod.env
platform: linux/amd64
environment:
- DATABASE_FILE=/data/chat_service_dev.db
ports:
- "4433:443"
- "8080:8080"
container_name: chat_service
volumes:
- ./data:/data
- ./priv/cert:/cert
We’ll update in the next step. Previously, we saved the chat_service.tar file. To copy it to the EC2 instance, use the following command:
scp -i "<name>.pem" chat_service.tar admin@<Public IPv4 DNS>:/home/admin
Once the file is on the EC2 instance, load the image from the tar file using:
docker load -i chat_service.tar
Next, retrieve the image ID by running:
docker image ls
Update the in your docker-compose.yml
file with the ID you obtained.
Next, run docker-compose up -d
to start the application. You can then access the chat service at:
<Public IPv4 address>:8080/chat_room?user_id=jack&channel_id=game_1
If there are no errors and no spinner is displayed on the LiveView page, it means the WebSocket connection has been successfully established!
It’s been a productive day! Don’t forget to terminate/stop the EC2 instance if you no longer need it to avoid incurring additional costs.
Overall Key Takeaways
Complete Workflow: The series provides a comprehensive guide from building a chat service with Elixir and Phoenix to deploying it on AWS EC2 using Docker.
Real-Time Capabilities: Emphasizes the use of Phoenix Channels for real-time communication, a crucial feature for chat applications.
Containerization Benefits: Highlights the benefits of using Docker for packaging and deploying applications, ensuring consistent environments and simplifying deployment.
Cloud Deployment: Covers the deployment process to AWS EC2, including instance configuration, security settings, and cost management.
Top comments (0)