๐Ÿš€ Day 39: GitHub Actions โ€“ Docker Layer Caching

Ritesh SinghRitesh Singh
5 min read

Welcome to Day 39 of my #100DaysOfDevOps! Today, weโ€™re diving into Docker Layer Caching in GitHub Actions to supercharge your CI/CD pipelines. By reusing previously built Docker layers, we can drastically reduce build times and optimize workflows. Letโ€™s get started! ๐Ÿณโšก #DevOps #GitHubActions


๐Ÿ“Œ Project: Docker Layer Caching Demo

This project demonstrates how to implement Docker Layer Caching in GitHub Actions using a simple Node.js application. The goal is to showcase how caching Docker layers can speed up builds by avoiding redundant work. ๐Ÿš€ #Docker #CI/CD


๐Ÿ“ Project Structure

Hereโ€™s how your project directory should look:

docker-layer-caching-demo/
โ”œโ”€โ”€ app.js                # Node.js application
โ”œโ”€โ”€ Dockerfile            # Docker configuration
โ”œโ”€โ”€ package.json          # Node.js dependencies and scripts
โ”œโ”€โ”€ package-lock.json     # Lock file for reproducible builds
โ””โ”€โ”€ .github/
    โ””โ”€โ”€ workflows/
        โ””โ”€โ”€ docker.yml    # GitHub Actions workflow for Docker builds

๐Ÿ› ๏ธ Step 1: Initialize the Project

Set up a new Node.js project:

mkdir docker-layer-caching-demo && cd docker-layer-caching-demo
npm init -y
npm install

The npm install command ensures dependencies are set up, though our simple app doesnโ€™t require additional packages for this demo. #NodeJS


๐Ÿง‘โ€๐Ÿ’ป Step 2: Create the Node.js Application

app.js

Create a simple HTTP server in app.js:

const http = require('http');
const PORT = 3000;

const server = http.createServer((req, res) => {
  res.end('๐Ÿš€ Docker Layer Caching in GitHub Actions!');
});

server.listen(PORT, () => {
  console.log(`Server running on http://localhost:${PORT}`);
});

This code sets up a Node.js server that responds with a message on port 3000. You can test it locally with:

node app.js

Visit http://localhost:3000 to see: "๐Ÿš€ Docker Layer Caching in GitHub Actions!" #JavaScript


๐Ÿณ Step 3: Create the Dockerfile

Create a Dockerfile to containerize the app:

FROM node:18

WORKDIR /app

COPY package*.json ./
RUN npm install

COPY . .

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

Why this structure?

  • Copying package*.json and running npm install before copying the app code ensures that the dependency layer is cached separately. This means changes to app.js wonโ€™t trigger a reinstall of dependencies, leveraging Dockerโ€™s layer caching. #Docker #Optimization

๐Ÿ“ฆ Step 4: Update package.json

Ensure your package.json is set up correctly:

{
  "name": "docker-layer-caching-demo",
  "version": "1.0.0",
  "main": "app.js",
  "scripts": {
    "start": "node app.js"
  },
  "license": "ISC"
}

The package-lock.json will be auto-generated when you run npm install. This lock file is critical for consistent caching in GitHub Actions. #NodeJS #Dependencies


โš™๏ธ Step 5: Set Up GitHub Actions Workflow

Create the workflow file at .github/workflows/docker.yml:

name: ๐Ÿš€ Docker Layer Caching

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: โฌ‡๏ธ Checkout code
        uses: actions/checkout@v4

      - name: ๐Ÿณ Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: ๐Ÿ“ฆ Docker Layer Cache
        uses: actions/cache@v4
        with:
          path: /tmp/.buildx-cache
          key: ${{ runner.os }}-docker-${{ github.sha }}
          restore-keys: |
            ${{ runner.os }}-docker-

      - name: ๐Ÿ—๏ธ Build Docker image
        run: |
          docker build \
            --build-arg BUILDKIT_INLINE_CACHE=1 \
            --cache-from=type=local,src=/tmp/.buildx-cache \
            --cache-to=type=local,dest=/tmp/.buildx-cache \
            -t myapp:latest .

Key Points:

  • Docker Buildx: Enables advanced build features, including layer caching.

  • Cache Configuration: Uses actions/cache@v4 to store Docker layers in /tmp/.buildx-cache.

  • Cache Key: Combines ${{ runner.os }}-docker- with the commit SHA (${{ github.sha }}) for unique cache entries.

  • Restore Keys: Allows fallback to previous caches if the exact SHA isnโ€™t found.

  • Buildkit: The --build-arg BUILDKIT_INLINE_CACHE=1 ensures cache metadata is included in the image. #GitHubActions #DockerBuild


๐Ÿš€ Step 6: Push to GitHub

Push your project to GitHub:

git init
git remote add origin https://github.com/ritesh355/docker-layer-caching-demo.git
git add .
git commit -m "Add Docker layer caching demo with GitHub Actions"
git push -u origin main

๐Ÿงช Step 7: Check Workflow and Cache

  1. Go to your GitHub repo โ†’ Actions tab.

  2. Watch the Docker Layer Caching workflow run.

First Run (Cache Miss)

Output:

Cache not found for: Linux-docker-...
...
[+] Building 56.4s (10/10) FINISHED

Result:

  • Docker layers are built from scratch.

  • Cache is created and stored in /tmp/.buildx-cache.

Second Run (Cache Hit)

Output:

Cache hit for: Linux-docker-c860ffe0118cab7eaf0092ade240cec129459046
Cache restored successfully
...
[+] Building 5.3s (10/10) FINISHED

Result:

  • Cached layers are reused.

  • Build time drops significantly (e.g., from ~50s to ~5s). ๐Ÿš€


๐Ÿ“ˆ Benefits of Docker Layer Caching

Build StageTime Without CacheTime With Cache
Initial Buildโณ ~50sโœ… Cached
Subsequent Buildsโšก ~5s๐Ÿš€ Super Fast!

Why it works:

  • Docker layers (e.g., npm install) are cached and reused unless package*.json changes.

  • The GitHub Actions cache persists layers between workflow runs, reducing redundant builds. #Optimization #Efficiency


๐Ÿ” How to Check Cache Status

In the GitHub Actions logs, look under the Docker Layer Cache step:

  • โœ… Cache hit: Layers were reused, speeding up the build.

  • โŒ Cache not found: A new cache was created.


๐Ÿ“š What I Learned

  • How to implement Docker Layer Caching in GitHub Actions using actions/cache@v4.

  • Using docker/setup-buildx-action and Buildkit for efficient Docker builds.

  • Crafting cache keys with package-lock.json hashes or commit SHAs for reliability.

  • Debugging cache hits/misses in GitHub Actions logs.

  • Optimizing CI/CD pipelines for faster, smarter builds. #Learning #DevOpsJourney


๐Ÿ”— Connect with Me

#Portfolio #Networking


๐ŸŽ‰ Congratulations!

Youโ€™ve mastered Docker Layer Caching in GitHub Actions, making your CI/CD pipelines faster and more efficient! Keep rocking your #100DaysOfDevOps journey! ๐Ÿ’ช #KeepLearning

Need help? Drop a comment or question, and Iโ€™ll guide you through any issues!

0
Subscribe to my newsletter

Read articles from Ritesh Singh directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ritesh Singh
Ritesh Singh

Hi, Iโ€™m Ritesh ๐Ÿ‘‹ Iโ€™m on a mission to become a DevOps Engineer โ€” and Iโ€™m learning in public every single day.With a full-time commitment of 8โ€“10 hours daily, Iโ€™m building skills in: โœ… Linuxโœ… Git & GitHubโœ… Docker & Kubernetesโœ… AWS EC2, S3โœ… Jenkins, GitHub Actionsโœ… Terraform, Prometheus, Grafana I post daily blogs on Hashnode, push projects to GitHub, and stay active on LinkedIn and Twitter/X. Letโ€™s connect, collaborate, and grow together ๐Ÿš€ #100DaysOfDevOps #LearningInPublic #DevOps