Utilizing GitLab Caching To Speed Up Build Process For Docker Based Project

Vinayak Pandey
3 min readJul 31, 2024

--

In this post, we’ll see how we can utilize caching in a GitLab pipeline to speed up build process for a docker based project

Step 1: Create a GitLab project named kaniko-caching with following files:

Dockerfile

# Dockerfile
FROM node:16-alpine

WORKDIR /usr/src/app

COPY app/package*.json ./
RUN npm install

COPY app .

EXPOSE 3000
CMD ["node", "index.js"]

.gitlab-ci.yml

stages:
- build_tar
- run_container

build_tar:
stage: build_tar
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
variables:
DOCKER_REGISTRY: ${AWS_ACCOUNT_ID}.dkr.ecr.us-east-1.amazonaws.com
ECR_REGISTRY_NAME: scanning
script:
- echo "{\"credsStore\":\"ecr-login\",\"credHelpers\":{\"$DOCKER_REGISTRY\":\"ecr-login\"}}" > /kaniko/.docker/config.json
- /kaniko/executor --context "./" --dockerfile "./Dockerfile" --no-push --destination output:latest --tarPath api.tar --cache=true --cache-repo=$DOCKER_REGISTRY/$ECR_REGISTRY_NAME --cache-run-layers --snapshot-mode=redo --cleanup --cache-ttl 720h0m0s --use-new-run
only:
- main
artifacts:
paths:
- "api.tar"
expire_in: 1 day

run_container:
stage: run_container
image: docker:latest
services:
- docker:dind
variables:
DOCKER_DRIVER: overlay2
needs:
- build_tar
dependencies:
- build_tar
script:
- docker load -i api.tar
- docker images
- docker run --rm output:latest

app/index.js

const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
res.send('Hello, World!');
});

app.listen(port, () => {
console.log(`App1 listening at http://localhost:${port}`);
});

app/package.json

{
"name": "sample-node-app",
"version": "1.0.0",
"description": "A sample Node.js application",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"author": "Your Name",
"license": "MIT",
"dependencies": {
"express": "^4.17.1",
"lodash": "^4.17.21",
"mongoose": "^6.0.14",
"axios": "^0.24.0",
"cors": "^2.8.5",
"dotenv": "^10.0.0",
"morgan": "^1.10.0",
"body-parser": "^1.19.0",
"moment": "^2.29.1",
"uuid": "^8.3.2"
}
}

Step 2: Create following GitLab CI/CD variables

AWS_ACCESS_KEY_ID
AWS_ACCOUNT_ID
AWS_SECRET_ACCESS_KEY

Step 3: Now run the pipeline. It took 36 seconds for image build step and kaniko pushed cache layer to ECR

Now make some changes to index.js file and re-run the pipeline. This time cache was used and imge build time got reduced to 24 seconds.

Edit: Instead of using access key and secret access key, you can also create OIDC IAM role for GitLab and use it for AWS authentication. For that pipeline can be changed to this

stages:
- get_ecr_token
- image_build
- run_container

.setup-script:
before_script:
- mkdir -p ~/.aws
- echo "${MY_OIDC_TOKEN}" > /tmp/web_identity_token
- echo -e
"[default]\nrole_arn=${ROLE_ARN}\nweb_identity_token_file=/tmp/web_identity_token"
> ~/.aws/config

get_ecr_token:
stage: get_ecr_token
variables:
ROLE_ARN: $GITLAB_ROLE_ARN
AWS_REGION: "us-east-1"
image:
name: amazon/aws-cli:latest
entrypoint:
- ""
id_tokens:
MY_OIDC_TOKEN:
aud: https://gitlab.com
before_script:
!reference [.setup-script, before_script]
script:
- token=$(aws ecr get-login-password --region $AWS_REGION)
- echo NONPROD_DOCKER_PASSWORD=$token > token.env
- ECR_TOKEN=$(aws ecr get-login-password --region $AWS_REGION)
- AUTH_TOKEN=$(echo -n "AWS:$ECR_TOKEN" | base64 -w 0)
- echo AUTH_TOKEN=$AUTH_TOKEN > token.env
artifacts:
reports:
dotenv: token.env

image_build:
stage: image_build
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
variables:
DOCKER_REGISTRY: ${AWS_ACCOUNT_ID}.dkr.ecr.us-east-1.amazonaws.com
needs:
- get_ecr_token
dependencies:
- get_ecr_token
script:
- mkdir -p /kaniko/.docker
- |
cat <<EOF > /kaniko/.docker/config.json
{
"auths": {
"${DOCKER_REGISTRY}": {
"auth": "${AUTH_TOKEN}"
}
}
}
EOF
- cat /kaniko/.docker/config.json
- /kaniko/executor --context "./" --dockerfile "./Dockerfile" --no-push --destination output:latest --tarPath api.tar --cache=true --cache-repo=${AWS_ACCOUNT_ID}.dkr.ecr.us-east-1.amazonaws.com/scanning --cache-run-layers --snapshot-mode=redo --cleanup --cache-ttl 720h0m0s --use-new-run
artifacts:
paths:
- "api.tar"
expire_in: 1 day

run_container:
stage: run_container
image: docker:latest
services:
- docker:dind
variables:
DOCKER_DRIVER: overlay2
needs:
- image_build
dependencies:
- image_build
script:
- docker load -i api.tar
- docker images
- docker run --rm output:latest

--

--

Vinayak Pandey
Vinayak Pandey

Written by Vinayak Pandey

Experienced Cloud Engineer with a knack of automation. Linkedin profile: https://www.linkedin.com/in/vinayakpandeyit/

No responses yet