TIL

KO

2022.01.26

ECS and Docker Experience - Part 1

  • Dockerizing
  • 1. django application
  • 2. nginx
  • ECS cluster - Fargate vs EC2
  • Uploading images to repository (feat. M1)

Dockerizing

First, we'll build server images using Docker. The images we'll build are the Django container image for the server and the nginx container image to be used in front of Django, totaling 2 images.

The reason for using nginx along with Django is that the runserver command used by Django is primarily intended for "development and testing." In fact, Django's official documentation doesn't recommend using runserver in production environments due to security and performance issues.

runserver is for development and testing

(Source: https://docs.djangoproject.com/en/2.2/ref/django-admin/#runserver)

For this reason, we use uWSGI, a type of WSGI (Web Server Gateway Interface), instead of runserver to run Django.

You might wonder, "Why use wsgi?"

  • WSGI servers are designed to handle many requests.
  • Frameworks are not designed to handle numerous requests optimally on their own, but this is determined by the server that runs the framework.

By using wsgi, we can leverage Django's web framework capabilities while adding nginx to the front to perform reverse proxy functions and achieve better performance.

Here's how to build each image:

1. django application

Dockerfile

FROM python:3.6
 
ENV PYTHONUNBUFFERED 1
 
ENV PATH="/scripts:${PATH}"
 
ENV ENV=dev # Assign different tags according to environment
 
WORKDIR /app
 
COPY . .
 
COPY ./scripts /scripts
 
RUN pip install -r requirements.txt --no-cache-dir 
 
RUN chmod +x /scripts/*
 
RUN mkdir -p /vol/web/media
RUN mkdir -p /vol/web/static
RUN adduser user --gecos "First Last,RoomNumber,WorkPhone,HomePhone" --disabled-password
RUN chown -R user:user /vol
RUN chmod -R 755 /vol/web
USER user
 
CMD ["entrypoint.sh"]

❓ Why use the --gecos and --disabled-password commands? ❗️ The --disabled-password option prevents unnecessary password-related error outputs. The --gecos option sets additional information related to the user. While --gecos isn't necessary for functionality, we assign dummy values to gecos to prevent unnecessary user setting-related error outputs since we'll be using GitHub Actions for management later.

entrypoint.sh - Manage commands like migrate, uwsgi in one file

#!/bin/sh
 
set -e
 
python manage.py collectstatic --noinput
 
python manage.py migrate --noinput
 
uwsgi --socket :8000 --master --enable-threads --module (filename).wsgi

Then run the build command in the directory where the Dockerfile is located.

docker build . (-t tag) (-f dockerfile-name)

2. nginx

Dockerfile

FROM nginxinc/nginx-unprivileged:1-alpine
 
COPY ./default.conf /etc/nginx/conf.d/default.conf
COPY ./uwsgi_params /etc/nginx/uwsgi_params
 
USER root
 
RUN mkdir -p /vol/static
RUN chmod 755 /vol/static
 
USER nginx

default.conf

server {
    listen 8080;
 
    location /static {
        alias /vol/static;
    }
 
    location / {
        uwsgi_pass 127.0.0.1:8000;
        include /etc/nginx/uwsgi_params;
    }
}

Then run the build command in the directory where the Dockerfile is located.

docker build . (-t tag) (-f dockerfile-name)

This allows users to access the nginx container through port 8080, and the nginx container can connect to the django container through port 8000.


ECS cluster - Fargate vs EC2

Before pushing the built images to ECR, we need to create a cluster suitable for our purpose.

AWS allows you to choose between EC2 and Fargate for cluster infrastructure. EC2 delivers higher efficiency in systems with predictable and stable CPU usage, while Fargate performs efficiently in environments with dynamic workloads.

Since Inpock Link frequently scales and usually has relatively low workloads, we ultimately chose Fargate, which allows us to use low-level CPU units (0.25).

Now it's time to push the created images to ECR!


Uploading images to repository (feat. M1)

(If you're not using an M1 chip environment, you can skip this section. Congratulations!)

This was the most challenging part of the project and where we spent the most time on image uploads 🥲 Normally, you can build images using the docker build ~ command. However, with the M1 chip, when running tasks in a cluster using built images, you'll encounter the following error:

exec format error

The reason is that the architecture of ECS tasks differs from images built with the M1 chip.

ECS task architecture is set to Linux/X86_64, while images built with the M1 chip have arm64 as the default architecture.

To solve this problem, you can use the docker buildx command.

docker buildx is an extension plugin for Docker commands that can build multi-architecture images. Additionally, you can build images in desired formats through custom builders that include the features you want.

Docker Buildx You can specify the desired architecture using the --platform option.

docker buildx build --platform linux/amd64 (-t tag) . (--no-cache) (-f Dockerfile name)

Reference links (Thank you so much to all the experts!)


Through these processes, we were able to successfully build server and nginx images and push them to ECR.

In Part 2, we'll create tasks and services using the generated images and proceed all the way to CodeDeploy!


For more detailed content and trial-and-error processes, you can also check here!