DEV Community

Aisalkyn Aidarova
Aisalkyn Aidarova

Posted on

Two-Day Homework — CI `needs` + Build + Docker

The goal is to reproduce this entire architecture independently:

Developer
   ↓
Feature Branch
   ↓
Pull Request
   ↓
┌──────── Lint ────────┐
│                      │
├──────── SonarQube ────┼──→ ALL PASS
│                      │       ↓
└──────── Trivy ────────┘     needs
                               ↓
                             Build
                               ↓
                             dist/
                               ↓
                           Dockerfile
                               ↓
                         Docker Image
                               ↓
                           Container
                               ↓
                      Host 8080 → 80
                               ↓
                             Nginx
                               ↓
                     Restaurant Company
Enter fullscreen mode Exit fullscreen mode

Part 1 — Git preparation

Start from the repository:

cd ~/restaurant-company

git status
git branch

git switch main
git pull origin main

git switch -c homework-needs-docker
Enter fullscreen mode Exit fullscreen mode

Verify:

git branch
git status
Enter fullscreen mode Exit fullscreen mode

Students must explain: What is main? Why do we create a feature branch? Why do we run git pull before creating the branch? What does git status tell us?


Part 2 — Review the three parallel CI jobs

Open:

cat .github/workflows/ci.yml
Enter fullscreen mode Exit fullscreen mode

Students must identify:

lint
sonarqube
trivy
Enter fullscreen mode Exit fullscreen mode

They should write answers to these questions:

What is a Job? What is a Runner? What is a Step? Why can Lint, SonarQube and Trivy run in parallel? What is the difference between parallel jobs and sequential steps? What does runs-on: ubuntu-latest mean?

They should draw:

               ┌── Lint
               │
Pull Request ──┼── SonarQube
               │
               └── Trivy
Enter fullscreen mode Exit fullscreen mode

Part 3 — Yesterday's main topic: needs

Students must add/review:

build:
  name: Build
  runs-on: ubuntu-latest

  needs:
    - lint
    - sonarqube
    - trivy
Enter fullscreen mode Exit fullscreen mode

They must explain every line.

Especially:

needs:
  - lint
  - sonarqube
  - trivy
Enter fullscreen mode Exit fullscreen mode

Written questions:

What does needs mean? What is a dependent job? What is an independent job? Are lint, sonarqube, and trivy job IDs or display names? Why shouldn't Build start immediately?

Then explain:

Lint       ✅
SonarQube  ✅
Trivy      ✅
              ↓
Build      ▶ RUN
Enter fullscreen mode Exit fullscreen mode

versus:

Lint       ✅
SonarQube  ✅
Trivy      ❌
              ↓
Build      ⏭ SKIPPED
Enter fullscreen mode Exit fullscreen mode

Students must answer:

What is the difference between FAILED and SKIPPED?


Part 4 — Build Job

Complete/review:

build:
  name: Build
  runs-on: ubuntu-latest

  needs:
    - lint
    - sonarqube
    - trivy

  steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: 22
        cache: npm

    - name: Install dependencies
      run: npm ci

    - name: Build application
      run: npm run build

    - name: Verify build
      run: ls -la dist
Enter fullscreen mode Exit fullscreen mode

Students explain:

Checkout
   ↓
Setup Node
   ↓
npm ci
   ↓
npm run build
   ↓
dist/
   ↓
Verify
Enter fullscreen mode Exit fullscreen mode

Written questions: What does npm ci do? Which file locks exact dependencies? Where does npm run build come from? What does Vite create? What is dist/? Why do we run ls -la dist?


Part 5 — Commit, Push and Pull Request

Before committing:

git status
git diff
Enter fullscreen mode Exit fullscreen mode

Then:

git add .github/workflows/ci.yml

git status

git commit -m "Add dependent build job"

git push -u origin homework-needs-docker
Enter fullscreen mode Exit fullscreen mode

Create a Pull Request:

homework-needs-docker
        ↓
   Pull Request
        ↓
       main
Enter fullscreen mode Exit fullscreen mode

Open GitHub Actions.

Take a screenshot showing the jobs.

Students should be able to explain:

        ┌── Lint ────────┐
        │                 │
PR ─────┼── SonarQube ────┼──→ Build
        │                 │
        └── Trivy ────────┘
Enter fullscreen mode Exit fullscreen mode

Part 6 — Docker Fundamentals

Now today's material.

Before touching commands, students write definitions for:

Docker, Dockerfile, Docker Image, Container, Container Runtime.

Then explain:

Dockerfile
    ↓
docker build
    ↓
Image
    ↓
docker run
    ↓
Container
Enter fullscreen mode Exit fullscreen mode

They must clearly answer:

What is the difference between an Image and a Container?


Part 7 — Study the Restaurant Company Dockerfile

Run:

cat Dockerfile
Enter fullscreen mode Exit fullscreen mode

Study:

FROM node:22-alpine AS builder

WORKDIR /app

COPY package*.json ./

RUN npm ci

COPY . .

RUN npm run build


FROM nginx:alpine

COPY nginx.conf /etc/nginx/conf.d/default.conf

COPY --from=builder /app/dist /usr/share/nginx/html

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]
Enter fullscreen mode Exit fullscreen mode

Students must explain every instruction:

FROM
AS builder
WORKDIR
COPY
RUN
COPY --from
EXPOSE
CMD
Enter fullscreen mode Exit fullscreen mode

Part 8 — Multi-stage Build

Students draw:

STAGE 1 — BUILDER
────────────────────

node:22-alpine
      ↓
package.json
package-lock.json
      ↓
npm ci
      ↓
Source Code
      ↓
npm run build
      ↓
/app/dist


          ↓ COPY


STAGE 2 — RUNTIME
────────────────────

nginx:alpine
      ↓
/usr/share/nginx/html
      ↓
Nginx
      ↓
Port 80
Enter fullscreen mode Exit fullscreen mode

Questions:

Why do we have two FROM instructions? What is a multi-stage build? Why do we need Node.js during Build? Why can Nginx serve the final frontend? What does COPY --from=builder mean?


Part 9 — Build the Docker Image

Run:

docker --version

docker build -t restaurant-company:homework .
Enter fullscreen mode Exit fullscreen mode

Then:

docker images
Enter fullscreen mode Exit fullscreen mode

Take a screenshot.

Students explain:

docker build
-t
restaurant-company
:homework
.
Enter fullscreen mode Exit fullscreen mode

Especially:

What does . mean?

Answer: current directory as the build context.


Part 10 — Run the Container

Run:

docker run -d \
  --name restaurant-homework \
  -p 8080:80 \
  restaurant-company:homework
Enter fullscreen mode Exit fullscreen mode

Verify:

docker ps
Enter fullscreen mode Exit fullscreen mode

Students explain:

docker run
-d
--name
-p
8080:80
restaurant-company:homework
Enter fullscreen mode Exit fullscreen mode

Draw:

EC2 HOST
Port 8080
    ↓
Docker
    ↓
CONTAINER
Port 80
    ↓
Nginx
Enter fullscreen mode Exit fullscreen mode

They must explain:

In 8080:80, which is Host and which is Container?


Part 11 — Go Inside the Container

Run:

docker exec -it restaurant-homework sh
Enter fullscreen mode Exit fullscreen mode

Now inside:

cat /etc/os-release

hostname

pwd
Enter fullscreen mode Exit fullscreen mode

Students answer:

My EC2 is Ubuntu. Why does the container show Alpine?

Then:

cd /usr/share/nginx/html

pwd

ls -la
Enter fullscreen mode Exit fullscreen mode

Inspect:

cat index.html

ls assets
Enter fullscreen mode Exit fullscreen mode

Then:

cat /etc/nginx/conf.d/default.conf
Enter fullscreen mode Exit fullscreen mode

Students must connect this to Dockerfile:

COPY --from=builder /app/dist /usr/share/nginx/html
Enter fullscreen mode Exit fullscreen mode

They should explain:

/app/dist
     ↓
COPY
     ↓
/usr/share/nginx/html
Enter fullscreen mode Exit fullscreen mode

Part 12 — Exit Without Stopping the Container

Run:

exit
Enter fullscreen mode Exit fullscreen mode

Then:

docker ps
Enter fullscreen mode Exit fullscreen mode

Students answer:

Why is the container still running after I typed exit?

They need to understand that they exited their interactive shell; the container's main Nginx process is still running.


Part 13 — Test with curl

From EC2:

curl -I http://localhost:8080
Enter fullscreen mode Exit fullscreen mode

Then:

curl http://localhost:8080
Enter fullscreen mode Exit fullscreen mode

Students should identify an HTTP response such as:

HTTP/1.1 200 OK
Server: nginx
Enter fullscreen mode Exit fullscreen mode

Explain the request:

curl
 ↓
localhost:8080
 ↓
Docker Port Mapping
 ↓
Container :80
 ↓
Nginx
 ↓
Website
Enter fullscreen mode Exit fullscreen mode

Take a screenshot.


Part 14 — Open Restaurant Company in Browser

Check AWS Security Group.

For the lab, allow the needed TCP 8080 access, preferably from the student's own IP when practical.

Then:

http://EC2-PUBLIC-IP:8080
Enter fullscreen mode Exit fullscreen mode

Take a screenshot showing the Restaurant Company website.

Students must draw the complete architecture:

Laptop
   ↓
Browser
   ↓
Internet
   ↓
EC2 Public IP :8080
   ↓
AWS Security Group
   ↓
EC2 Host Port 8080
   ↓
Docker Port Mapping
   ↓
Container Port 80
   ↓
Nginx
   ↓
/usr/share/nginx/html
   ↓
Restaurant Company
Enter fullscreen mode Exit fullscreen mode

Part 15 — Troubleshooting Incident

Now deliberately break the application:

docker stop restaurant-homework
Enter fullscreen mode Exit fullscreen mode

Try:

curl -I http://localhost:8080
Enter fullscreen mode Exit fullscreen mode

Then:

docker ps
Enter fullscreen mode Exit fullscreen mode

Students should investigate:

docker ps -a
Enter fullscreen mode Exit fullscreen mode

Find the problem.

Fix:

docker start restaurant-homework
Enter fullscreen mode Exit fullscreen mode

Verify:

docker ps

curl -I http://localhost:8080
Enter fullscreen mode Exit fullscreen mode

Refresh the browser.

Students write:

CHECK
 ↓
docker ps

FIND
 ↓
Container stopped

FIX
 ↓
docker start restaurant-homework

VERIFY
 ↓
docker ps
curl
browser
Enter fullscreen mode Exit fullscreen mode

This should connect to your troubleshooting model:

CHECK → FIND → FIX → VERIFY


Part 16 — Command Challenge Without Notes

Students should be able to explain these commands without copying definitions:

docker build -t restaurant-company:homework .

docker images

docker run -d --name restaurant-homework -p 8080:80 restaurant-company:homework

docker ps

docker ps -a

docker exec -it restaurant-homework sh

docker stop restaurant-homework

docker start restaurant-homework

curl -I localhost:8080
Enter fullscreen mode Exit fullscreen mode

Part 17 — Interview Questions

Students should write answers in their own words to these questions:

What is Docker? What problem does Docker solve? What is a Dockerfile? What is a Docker Image? What is a Container? Image vs Container? What does docker build do? What does docker run do? What does docker exec do? docker ps vs docker ps -a? What does -p 8080:80 mean? What is a multi-stage Docker build? Why does our first stage use Node.js? Why does our second stage use Nginx? What is dist/? What does COPY --from=builder do? Why is the EC2 Ubuntu but the container Alpine? What is needs in GitHub Actions? Why do Lint/SonarQube/Trivy run in parallel? Why does Build wait? What happens to Build when a required job fails?

Interview answer to practice

“In our CI pipeline, Lint, SonarQube and Trivy run as independent jobs in parallel. Our Build job depends on those required checks using needs. After the checks pass, we build the Vite application and produce the dist directory. We then use a multi-stage Dockerfile: Node.js builds the application, and the final Nginx stage serves the built files. We build a Docker image and run it as a container with host port 8080 mapped to container port 80.”

Top comments (0)