AWS Prerequisites #
Create Elastic Container Registry Repository #
# Create a repository
aws ecr create-repository --repository-name example-application --region eu-central-1
# Shell output:
{
"repository": {
"repositoryArn": "arn:aws:ecr:eu-central-1:012345678912:repository/example-application",
"registryId": "012345678912",
"repositoryName": "example-application",
"repositoryUri": "012345678912.dkr.ecr.eu-central-1.amazonaws.com/example-application",
"createdAt": "2024-12-14T11:00:07.003000+00:00",
"imageTagMutability": "MUTABLE",
"imageScanningConfiguration": {
"scanOnPush": false
},
"encryptionConfiguration": {
"encryptionType": "AES256"
}
}
}
IAM User & Permissions #
Create IAM User #
# Create a new IAM user with the name "ecr-user"
aws iam create-user --user-name ecr-user
# Shell output:
{
"User": {
"Path": "/",
"UserName": "ecr-user",
"UserId": "AIDARCHUALIN47DNKQC4L",
"Arn": "arn:aws:iam::012345678912:user/ecr-user",
"CreateDate": "2024-12-14T09:55:52+00:00"
}
}
Create Access Keys for the User #
# Create Access Keys for the user
aws iam create-access-key --user-name ecr-user
# Shell output:
{
"AccessKey": {
"UserName": "ecr-user",
"AccessKeyId": "AKIARCHUALIN2XLCCOHZ",
"Status": "Active",
"SecretAccessKey": "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",
"CreateDate": "2024-12-14T09:57:16+00:00"
}
}
Copy the Access Key and Secret Access Key:
-
“AccessKeyId”:
AKIARCHUALIN2XLCCOHZ
-
“SecretAccessKey”:
xnndW1/tbkUmJDfjB/TERhDrN4UdexHcqZ5RRu3x
Attach Policy to User #
ECR Policies:
-
AmazonEC2ContainerRegistryReadOnly
Pull permission -
AmazonEC2ContainerRegistryFullAccess
Push and Pull permission
# Attach the "AmazonEC2ContainerRegistryFullAccess" policy to the user:
aws iam attach-user-policy --user-name ecr-user --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess
Verify the User Policy #
# Confirm the policy is attached to the user
aws iam list-attached-user-policies --user-name ecr-user
# Shell output:
{
"AttachedPolicies": [
{
"PolicyName": "AmazonEC2ContainerRegistryFullAccess",
"PolicyArn": "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess"
}
]
}
GitLab Repository #
CI/CD Variables #
-
Go to: (Project) “Settings” > “CI/CD”
-
Expand the “Variables” section
-
Click “Add variable”
-
Select type “Variable (default)”
-
Unflag the “Protect variable” option
Add the following variables:
-
Key:
AWS_ACCOUNT_ID
Value:012345678912
-
Key:
AWS_REGION
Value:eu-central-1
-
Key:
AWS_ACCESS_KEY_ID
Value:AKIARCHUALIN2XLCCOHZ
-
key:
AWS_SECRET_ACCESS_KEY
Value:xnndW1/tbkUmJDfjB/TERhDrN4UdexHcqZ5RRu3x
CI Pipeline Manifest #
- .gitlab-ci.yml
variables:
# Define ECR repository name
IMAGE_NAME: example-application
TAG_LATEST: $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$IMAGE_NAME:latest
TAG_COMMIT: $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$IMAGE_NAME:$CI_COMMIT_SHORT_SHA
stages:
- build
# Build image and push it to AWS ECR repository
build_image:
image: docker:stable
stage: build
services:
- name: docker:23.0.6-dind
command: ["--tls=false"]
variables:
DOCKER_TLS_CERTDIR: ""
before_script:
# Install AWS CLI
- apk add --no-cache python3 py3-pip
- pip3 install --no-cache-dir awscli
script:
# Login the AWS ECR
- aws ecr get-login-password --region $AWS_REGION |
docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com
# Try pulling the latest image, keep going if it does not exist
- docker pull $TAG_LATEST || true
# Build image
- docker build --cache-from $TAG_LATEST -t $TAG_COMMIT -t $TAG_LATEST -f Dockerfile .
# Push image to AWS ECR repository
- docker push $TAG_COMMIT
- docker push $TAG_LATEST
rules:
# Rule: Run this job only for the main branch and if the specified Dockerfile exists
- if: $CI_COMMIT_BRANCH == "main"
exists:
- Dockerfile
Example Application #
Dockerfile #
- Dockerfile
# Use the official Caddy image as the base
FROM caddy:alpine
# Create a non-root user "caddy"
RUN addgroup -S caddy && adduser -S -G caddy caddy
# Adjust permissions
RUN mkdir -p /usr/share/caddy && \
chown -R caddy:caddy /usr/share/caddy /config /data
# Copy website files into the container
ADD index.html /usr/share/caddy/
# Switch to the non-root user
USER caddy
# Expose the default Caddy port
EXPOSE 80
HTML File #
- index.html
<!DOCTYPE html>
<html>
<head>
<title>jklug.work</title>
</head>
<body>
<h1>Some HTML</h1>
<p>Example Application<br></p>
</body>
</html>
Cleanup #
Delete Elastic Container Registry #
# Delete the ECR repository
aws ecr delete-repository --repository-name example-application --region eu-central-1 --force
Delete IAM User #
# Detach the policies attached to the user
aws iam detach-user-policy --user-name ecr-user --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess
# List the access keys for the user
aws iam list-access-keys --user-name ecr-user
# Shell output:
{
"AccessKeyMetadata": [
{
"UserName": "ecr-user",
"AccessKeyId": "AKIARCHUALIN2XLCCOHZ",
"Status": "Active",
"CreateDate": "2024-12-14T09:57:16+00:00"
}
]
}
# Delete the access keys
aws iam delete-access-key --user-name ecr-user --access-key-id AKIARCHUALIN2XLCCOHZ
# Delete the "ecr-user" IAM user
aws iam delete-user --user-name ecr-user