Skip to content

Commit db975fe

Browse files
author
Mikaël Bouchez
committed
feat(ci): add 4th course
1 parent 527bf19 commit db975fe

File tree

3 files changed

+160
-2
lines changed

3 files changed

+160
-2
lines changed

.github/workflows/ci.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,43 @@ jobs:
6363
- name: Report Coverage
6464
if: always()
6565
uses: davelosert/vitest-coverage-report-action@v2
66+
67+
build-and-push:
68+
needs: [lint, verify-typescript-types, code-coverage]
69+
runs-on: ubuntu-latest
70+
permissions:
71+
contents: read
72+
packages: write
73+
steps:
74+
- name: Checkout repository
75+
uses: actions/checkout@v4
76+
77+
- name: Set up Docker Buildx
78+
uses: docker/setup-buildx-action@v3
79+
80+
- name: Log in to GitHub Container Registry
81+
uses: docker/login-action@v3
82+
with:
83+
registry: ghcr.io
84+
username: ${{ github.actor }}
85+
password: ${{ secrets.GITHUB_TOKEN }}
86+
87+
- name: Extract metadata for Docker
88+
id: meta
89+
uses: docker/metadata-action@v5
90+
with:
91+
images: ghcr.io/${{ github.repository }}
92+
tags: |
93+
type=ref,event=branch
94+
type=sha,format=short
95+
96+
- name: Build and push Docker image
97+
uses: docker/build-push-action@v5
98+
with:
99+
context: .
100+
push: true
101+
platforms: linux/amd64,linux/arm64
102+
tags: ${{ steps.meta.outputs.tags }}
103+
labels: ${{ steps.meta.outputs.labels }}
104+
cache-from: type=gha
105+
cache-to: type=gha,mode=max

Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ WORKDIR /app
1010

1111
COPY --from=build /app/node_modules ./node_modules
1212
COPY --from=build /app/build ./build
13+
COPY --from=build /app/conf ./build/conf
14+
COPY --from=build /app/data ./build/data
1315

1416
EXPOSE 3030
1517
CMD ["node", "build/server.js"]

README.md

Lines changed: 118 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,17 +220,133 @@ Test coverage highlights which parts of the code are tested and which aren't, he
220220

221221
</details>
222222

223+
### Job 4: Docker Build and Push
224+
225+
**Exercise**:
226+
Create a job called `build-and-push` that builds a Docker image from the Dockerfile and pushes it to GitHub Container Registry (GHCR). The job should:
227+
228+
1. Only run when the previous jobs (lint, verify-typescript-types, code-coverage) have completed successfully
229+
2. Checkout the repository code
230+
3. Set up Docker Buildx for multi-platform builds
231+
4. Log in to GitHub Container Registry using GitHub secrets
232+
5. Extract metadata from Git for proper image tagging
233+
6. Build and push the Docker image with appropriate tags
234+
235+
<details>
236+
<summary>Expand</summary>
237+
238+
**Solution**:
239+
240+
```yaml
241+
build-and-push:
242+
needs: [lint, verify-typescript-types, code-coverage]
243+
runs-on: ubuntu-latest
244+
permissions:
245+
contents: read
246+
packages: write
247+
steps:
248+
- name: Checkout repository
249+
uses: actions/checkout@v4
250+
251+
- name: Set up Docker Buildx
252+
uses: docker/setup-buildx-action@v3
253+
254+
- name: Log in to GitHub Container Registry
255+
uses: docker/login-action@v3
256+
with:
257+
registry: ghcr.io
258+
username: ${{ github.actor }}
259+
password: ${{ secrets.GITHUB_TOKEN }}
260+
261+
- name: Extract metadata for Docker
262+
id: meta
263+
uses: docker/metadata-action@v5
264+
with:
265+
images: ghcr.io/${{ github.repository }}
266+
tags: |
267+
type=ref,event=branch
268+
type=sha,format=short
269+
270+
- name: Build and push Docker image
271+
uses: docker/build-push-action@v5
272+
with:
273+
context: .
274+
push: true
275+
platforms: linux/amd64,linux/arm64
276+
tags: ${{ steps.meta.outputs.tags }}
277+
labels: ${{ steps.meta.outputs.labels }}
278+
cache-from: type=gha
279+
cache-to: type=gha,mode=max
280+
```
281+
282+
**Explanation:**
283+
284+
- `needs: [lint, verify-typescript-types, code-coverage]`: This ensures the job only runs after the previous jobs have completed successfully, creating a pipeline.
285+
286+
- `permissions`: Explicitly sets the required permissions for the GITHUB_TOKEN to read repository contents and write to the GitHub Packages registry.
287+
288+
- `docker/setup-buildx-action@v3`: Sets up Docker Buildx, which provides enhanced build capabilities including better caching and multi-platform builds.
289+
290+
- `docker/login-action@v3`: Authenticates with GitHub Container Registry using the automatically provided GITHUB_TOKEN.
291+
292+
- `docker/metadata-action@v5`: Extracts metadata from Git to create appropriate tags and labels for the Docker image:
293+
294+
- `type=ref,event=branch`: Tags the image with the branch name (e.g., `main`)
295+
- `type=sha,format=short`: Tags the image with the short Git commit SHA for easier identification
296+
297+
- `docker/build-push-action@v5`: Builds and pushes the Docker image with:
298+
- Multi-platform support for both AMD64 (standard x86 processors) and ARM64 (like Apple Silicon)
299+
- GitHub Actions cache integration for faster builds
300+
- Tags and labels from the metadata action
301+
- Automatic push to the registry
302+
303+
#### What you've learned:
304+
305+
**Skills acquired:**
306+
307+
- 🔄 **CI/CD Pipeline Construction**: You've created a complete pipeline from code quality checks to deployment, learning how jobs can depend on each other with the `needs` keyword.
308+
- 🐳 **Docker Integration**: You've learned how to build and push multi-architecture Docker images (AMD64 and ARM64) as part of your CI/CD pipeline.
309+
- 🔑 **Secure Authentication**: You've used GitHub's built-in token system to securely authenticate with the container registry without exposing credentials.
310+
- 🏷️ **Image Tagging Strategies**: You've implemented best practices for versioning container images using Git metadata.
311+
- 🚀 **Deployment Automation**: You've automated the deployment process, ensuring that only code that passes quality checks gets deployed.
312+
313+
**Why it matters:**
314+
315+
Containerization is a critical part of modern application deployment. By automating the build and push process, you ensure consistent, reproducible deployments and eliminate manual steps that could introduce errors. This completes the CI/CD pipeline, taking your code from commit to deployable artifact.
316+
317+
**Using your container image:**
318+
319+
Once pushed, your image will be available at `ghcr.io/ekino/githubworkflow-handson-nodejs` with two tags:
320+
321+
- Branch name tag: `ghcr.io/ekino/githubworkflow-handson-nodejs:main` (or your branch name)
322+
- Short SHA tag: `ghcr.io/ekino/githubworkflow-handson-nodejs:a1b2c3d` (abbreviated commit hash)
323+
324+
You can pull either version:
325+
326+
```bash
327+
# Pull by branch name
328+
docker pull ghcr.io/ekino/githubworkflow-handson-nodejs:main
329+
330+
# Pull by specific commit
331+
docker pull ghcr.io/ekino/githubworkflow-handson-nodejs:a1b2c3d
332+
```
333+
334+
The multi-architecture support means the same image works on both Intel/AMD machines and ARM-based systems like Apple Silicon Macs.
335+
336+
</details>
337+
223338
### Conclusion:
224339

225340
<details>
226341
<summary>Expand</summary>
227342

228-
With these three jobs, youve built a basic **quality pipeline** for any Node.js project:
343+
With these four jobs, you've built a complete **CI/CD pipeline** for any Node.js project:
229344

230345
- **Linting** ensures a clean codebase.
231346
- **Typing** ensures static correctness.
232347
- **Testing & Coverage** ensure reliability and confidence.
348+
- **Docker Build & Push** automates deployment and ensures only quality code is deployed.
233349

234-
You now know how to set up **automated checks on every push or pull request**, forming the foundation of a **collaborative development workflow**.
350+
You now know how to set up **automated checks on every push or pull request**, forming the foundation of a **collaborative development workflow** that extends all the way to deployment.
235351

236352
</details>

0 commit comments

Comments
 (0)