This project is a sample application designed to demonstrate various development and deployment practices.
- Dockerize: Containerize the application using Docker to ensure consistency across different environments.
- docker-compose for local development: Use docker-compose to set up the local development environment, allowing for easy management of multi-container applications.
- GitHub Actions workflow for CI/CD: Implement continuous integration and continuous deployment using GitHub Actions to automate testing, building, and deployment processes.
This Dockerfile is designed to build and run a sample Python application using a multi-stage build process. The multi-stage build ensures that the final image is small, secure, and contains only the necessary runtime dependencies.
-
Base Image:
- Uses
python:3.12.5-slim-bullseye
as the base image for building dependencies. - This image is slim and secure, reducing potential vulnerabilities.
- Uses
-
System Dependencies:
- Installs minimal system dependencies required for setup using
apt-get
. - Cleans up package lists to reduce image size.
- Installs minimal system dependencies required for setup using
-
Poetry Installation:
- Installs the Poetry package manager using the official installation script.
- Sets environment variables for Poetry and Python to disable interaction and prevent creating virtual environments.
-
Working Directory:
- Sets the working directory to
/app
.
- Sets the working directory to
-
Dependency Management Files:
- Copies
pyproject.toml
andpoetry.toml
to the working directory. - This allows better caching of dependency layers.
- Copies
-
Project Dependencies:
- Configures Poetry to limit installation workers and installs only the main dependencies, excluding development dependencies.
-
Base Image:
- Uses
python:3.12.5-slim-bullseye
as the base image for the final runtime. - This image is clean and slim, ensuring a minimal runtime environment.
- Uses
-
Runtime Dependencies:
- Installs minimal runtime dependencies using
apt-get
. - Cleans up package lists to reduce image size.
- Installs minimal runtime dependencies using
-
Non-Root User:
- Creates a non-root user (
appuser
) for improved security, following the principle of least privilege.
- Creates a non-root user (
-
Working Directory:
- Sets the working directory to
/app
.
- Sets the working directory to
-
Copy Dependencies:
- Copies installed dependencies from the builder stage to the runtime image.
- This keeps the runtime image small and clean.
-
Copy Application Code:
- Copies the application source code (
main.py
,run.sh
,.env
) to the working directory.
- Copies the application source code (
PYTHONFAULTHANDLER=1
: Improved error tracing.PYTHONUNBUFFERED=1
: Prevents output buffering.PYTHONHASHSEED=random
: Randomizes hash seed for security.PYTHONDONTWRITEBYTECODE=1
: Prevents.pyc
file generation.
- Non-root user execution.
- Minimal image size.
- Environment variable protection.
- Read-only file system.
- Dropped Linux capabilities.
Note: Refer to the comments in the Dockerfile for more details.
This docker-compose.yml
file sets up the local development environment for the sample Python application. It defines the services, volumes, and networks required to run the application in a containerized environment.
- Build Configuration:
- Context: The build context is set to the current directory (
.
). - Dockerfile: Uses the
Dockerfile
in the current directory to build the image.
- Context: The build context is set to the current directory (
- Port Mapping:
- Maps port
3000
on the host to port3000
in the container. - Only accessible from
127.0.0.1
for security.
- Maps port
- Volumes:
- Bind Mount: Mounts the current directory to
/app
in the container. - Read-Only: The bind mount is set to read-only for security.
- Bind Mount: Mounts the current directory to
- Linux Capabilities Management:
- Drop All Capabilities: Drops all default Linux capabilities.
- Add Necessary Capability: Adds only the
NET_BIND_SERVICE
capability.
- Filesystem:
- Read-Only Root Filesystem: Sets the root filesystem to read-only.
- Temporary Filesystems: Creates temporary filesystems for
tmp
and/run
.
- Security Options:
- No New Privileges: Prevents the container from gaining new privileges.
- Restart Policy:
- On-Failure: Restarts the container only on failure, preventing infinite restarts.
- Logging Configuration:
- Driver: Uses the
json-file
logging driver. - Options:
- Max Size: Limits the maximum log file size to
200k
. - Max File: Limits the maximum number of log files to
3
.
- Max Size: Limits the maximum log file size to
- Driver: Uses the
- Environment Variables: Ensure that the necessary environment variables are set in the
.env
file. - Application Code: The application source code should be in the current directory and will be mounted to
/app
in the container. - Security: The configuration follows best practices for security, including running as a non-root user, using a read-only filesystem, and dropping unnecessary Linux capabilities.
To build and run the Docker container using Docker Compose, use the following commands:
docker-compose build
docker-compose up
docker-compose down
- Add
python-dotenv
library topyproject.toml
to manage environment variables. - Import
python-dotenv
inmain.py
to load environment variables from a.env
file. - Modify
run.sh
script as necessary to ensure the application runs correctly with the new setup.
This cicd.yaml
file defines the CI/CD pipeline for the DevOps Test App using GitHub Actions. The pipeline automates the processes of building, testing, and deploying the application to Amazon ECS.
The workflow is triggered on the following events:
- Push to the
main
branch - Pull request to the
main
branch
The workflow requires the following permissions:
id-token: write
contents: read
The following environment variables are used in the workflow:
AWS_REGION
: The AWS region where the resources are located.ECR_REPOSITORY
: The name of the ECR repository.ECS_CLUSTER
: The name of the ECS cluster.ECS_SERVICE
: The name of the ECS service.ECS_TASK_DEFINITION
: The path to the ECS task definition file.ECS_CONTAINER_NAME
: The name of the ECS container.
The following secrets are used in the workflow:
AWS_ROLE_ARN
: The ARN of the AWS role to assume.AWS_ACCOUNT_ID
: The AWS account ID.
This job runs on ubuntu-latest
and performs the following steps:
- Checkout Code:
- Uses the
actions/checkout@v4
action to check out the code from the repository.
- Uses the
- Set up Python:
- Uses the
actions/setup-python@v4
action to set up Python 3.12.5.
- Uses the
- Install Poetry:
- Installs Poetry using the official installation script.
- Adds Poetry to the GitHub Actions PATH.
- Install Dependencies:
- Configures Poetry to not create virtual environments.
- Locks dependencies and installs them.
- Run Tests:
- Runs the tests using
pytest
.
- Runs the tests using
This job depends on the ci
job and runs on ubuntu-latest
. It performs the following steps:
- Checkout Code:
- Uses the
actions/checkout@v4
action to check out the code from the repository.
- Uses the
- Create .env file:
- Creates a .env file and populates it with necessary environment variables.
- Replace placeholders in task definition:
- Replace the placeholders in the task definition by substituting
{{AWS_ACCOUNT_ID}}
and{{AWS_REGION}}
with the corresponding values stored in GitHub Secrets.
- Replace the placeholders in the task definition by substituting
- Validate Task Definition:
- Validates the ECS task definition file using
jq
.
- Validates the ECS task definition file using
- Configure AWS Credentials:
- Uses the
aws-actions/configure-aws-credentials@v4
action to configure AWS credentials.
- Uses the
- Login to Amazon ECR:
- Uses the
aws-actions/amazon-ecr-login@v2
action to log in to Amazon ECR.
- Uses the
- Set up Docker Buildx:
- Uses the
docker/setup-buildx-action@v3
action to set up Docker Buildx.
- Uses the
- Build Docker Image:
- Uses the
docker/build-push-action@v5
action to build and push the Docker image to Amazon ECR.
- Uses the
- Render Amazon ECS Task Definition:
- Uses the
aws-actions/amazon-ecs-render-task-definition@v1
action to render the ECS task definition.
- Uses the
- Deploy to Amazon ECS Service:
- Uses the
aws-actions/amazon-ecs-deploy-task-definition@v2
action to deploy the task definition to the ECS service.
- Uses the
The ECS task definition is located at .aws/task-definition.json
. It defines the following:
- Family: The name of the task definition family.
- Task Role ARN: The ARN of the IAM role that the task can assume.
- Execution Role ARN: The ARN of the IAM role that grants the ECS agent permission to pull images and publish logs.
- Network Mode: The Docker networking mode to use for the containers in the task.
- Requires Compatibilities: Specifies that the task requires Fargate compatibility.
- CPU and Memory: The amount of CPU and memory used by the task.
- Container Definitions: Defines the containers in the task, including:
- Name: The name of the container.
- Image: The Docker image to use for the container.
- CPU and Memory: The amount of CPU and memory allocated to the container.
- Port Mappings: The port mappings for the container.
- Essential: Specifies whether the container is essential.
- Log Configuration: The log configuration for the container, using AWS CloudWatch Logs.
To use this CI/CD pipeline, ensure that the necessary environment variables are set in the GitHub repository settings. The pipeline will automatically run on push and pull request events to the main
branch.
Refer to this link for more details about the infrastructure: https://github.com/rhinozD/sample-terraform