Skip to content

Commit 5d33dee

Browse files
authored
Build docker image (#6)
* Build docker image Implemented Dockerfile and docker-compose.yaml. Inlcuded docker build step in deploy workflow. * Fix hadolint reported issues Add progress bar for wget and specify shell options to fix hadolint issues DL3047 and DL4006. * Change shell to bash Changed shell to bash since ash shell does not exist in bitnami/node image * Login to ECR and push image Added steps to deploy workflow for logging in to ECR and push the docker image that was build. Output the ECR image url. * Add name and fix typos for deploy workflow Add name for linter and test jobs. Updated name for vars, build and push as well as deploy steps on deploy job. * Fix error from copy-paste detector linter Created JSON file for response of API and test to avoid duplicationa
1 parent 57e707a commit 5d33dee

File tree

11 files changed

+168
-42
lines changed

11 files changed

+168
-42
lines changed

.cspell.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,13 @@
2525
"DEVSKIM",
2626
"gitmessage",
2727
"uuidv",
28-
"EDITMSG"
28+
"EDITMSG",
29+
"tsbuildinfo",
30+
"bitnami",
31+
"healthcheck",
32+
"cpus",
33+
"pipefail",
34+
"giga"
2935
],
3036
"version": "0.2"
3137
}

.dockerignore

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
**/.DS_Store
2+
**/.git
3+
**/.github
4+
**/.vscode
5+
**/coverage
6+
**/dist
7+
**/node_modules
8+
**/*.spec.ts
9+
**/.editorconfig
10+
11+
**/.eslintignore
12+
**/.eslintrc.json
13+
**/.cspell.json
14+
**/.jscpd.json
15+
**/.mega-linter.yml
16+
**/.prettierignore
17+
**/.prettierrc.json
18+
**/LICENSE
19+
**/.env
20+
**/.env.dist
21+
**/.gitignore
22+
**/.gitmessage
23+
**/jest.config.*
24+
**/*.log
25+
**/*.md
26+
**/*.tsbuildinfo
27+
28+
.dockerignore
29+
**/Dockerfile

.github/workflows/deploy.yml

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,52 @@ on:
1616

1717
jobs:
1818
linter:
19+
name: Linters
1920
uses: ./.github/workflows/mega-linter.yml
2021
permissions:
2122
# Give the default GITHUB_TOKEN write permission to commit and push, comment issues & post new PR
2223
contents: write
2324
issues: write
2425
pull-requests: write
2526
tests:
27+
name: Tests
2628
uses: ./.github/workflows/tests.yml
2729
deploy:
28-
name: Run Deployment
30+
name: Deployment
2931
runs-on: ubuntu-latest
3032
needs:
3133
- linter
3234
- tests
3335
steps:
3436
- name: Checkout
3537
uses: actions/checkout@v3
36-
- name: deploy
38+
39+
- name: Declare tag variable
40+
id: vars
41+
shell: bash
42+
run: |
43+
echo "tag=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
44+
45+
- name: Configure AWS credentials
46+
uses: aws-actions/configure-aws-credentials@v1
47+
with:
48+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
49+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
50+
aws-region: ${{ secrets.AWS_REGION }}
51+
52+
- name: Login to Amazon ECR
53+
id: login-ecr
54+
uses: aws-actions/amazon-ecr-login@v1
55+
56+
- name: Build and push the tagged Docker image
57+
env:
58+
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
59+
ECR_REPOSITORY: ${{ secrets.ECR_REPOSITORY_NAME }}
60+
IMAGE_TAG: ${{ steps.vars.outputs.tag }}
61+
run: |
62+
docker build . --file Dockerfile --tag $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
63+
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
64+
echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT
65+
66+
- name: Deploy
3767
run: echo "Application is deployed"

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ node_modules
22
.env
33
megalinter-reports/
44
dist
5-
access.log
5+
**/access.log
66
coverage

Dockerfile

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
FROM bitnami/node:20.3.1-debian-11-r3@sha256:348cf7ec9f6901daf791ace21846fabe1c372f907919e99b07a2dbbd1b0b0052 as builder
2+
3+
WORKDIR /code
4+
5+
COPY . .
6+
7+
# Set SHELL flags for RUN commands to allow -e and pipefail
8+
# Rationale: https://github.com/hadolint/hadolint/wiki/DL4006
9+
SHELL ["/bin/bash", "-eo", "pipefail", "-c"]
10+
11+
RUN yarn install \
12+
&& yarn build \
13+
&& rm -rf node_modules \
14+
&& yarn install --production
15+
16+
# Set progress bar for wget to avoid excessively bloated build logs
17+
# Rationale: https://github.com/hadolint/hadolint/wiki/DL3047
18+
RUN wget --progress=dot:giga https://gobinaries.com/tj/node-prune --output-document - | /bin/sh \
19+
&& node-prune
20+
21+
FROM node:20.3.1-bullseye-slim@sha256:18cfcccefacb1bb2ca8df40f881cca0f1eedeae020154e6b07eddad0073bdc8e
22+
23+
WORKDIR /app
24+
25+
COPY --from=builder /code/node_modules /app/node_modules
26+
COPY --from=builder /code/dist /app
27+
COPY --from=builder /code/views /app/views
28+
29+
RUN mkdir -p /app/node_modules/.cache \
30+
&& chown -R 1001:1001 /app/node_modules/.cache \
31+
&& touch /app/access.log \
32+
&& chown 1001:1001 /app/access.log
33+
34+
USER 1001:1001
35+
36+
HEALTHCHECK CMD curl --fail http://localhost:3000/hello-world || exit 1
37+
38+
CMD ["node", "./index.js"]

docker-compose.yaml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
version: '3.7'
3+
4+
services:
5+
demo-app:
6+
platform: linux/amd64
7+
build:
8+
context: .
9+
dockerfile: Dockerfile
10+
env_file:
11+
- .env
12+
ports:
13+
- '127.0.0.1:3000:3000'
14+
deploy:
15+
resources:
16+
limits:
17+
cpus: '0.3'
18+
memory: 256M
19+
reservations:
20+
cpus: '0.1'
21+
memory: 128M
22+
networks:
23+
- demo-app
24+
restart: always
25+
pid: 'demo-app:demo-app'
26+
security_opt:
27+
- no-new-privileges:true
28+
healthcheck:
29+
test: curl --fail -s http://localhost:3000/hello-world || exit 1
30+
interval: 1m30s
31+
timeout: 10s
32+
retries: 3
33+
cap_drop:
34+
- all
35+
networks:
36+
demo-app:

src/app.spec.ts

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* globals describe, expect, it */
22
import request from 'supertest'
3+
import response from './database/hello-world.json'
34
import app from './app'
45

56
process.env.AUTH_TOKEN = 'test'
@@ -10,23 +11,6 @@ describe('Hello World API Endpoint', function () {
1011
.get('/api/v1/hello-world')
1112
.set('Authorization', 'Basic test')
1213
expect(res.statusCode).toEqual(200)
13-
expect(res.body).toEqual({
14-
status: 'success',
15-
message: 'Hello World API!',
16-
products: [
17-
{
18-
id: '1',
19-
name: 'MacBook Pro'
20-
},
21-
{
22-
id: '2',
23-
name: 'HP'
24-
},
25-
{
26-
id: '3',
27-
name: 'Dell'
28-
}
29-
]
30-
})
14+
expect(res.body).toEqual(response)
3115
})
3216
})

src/app.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ app.use(bodyParser.json())
3636
app.use(cors())
3737

3838
// adding morgan to log HTTP requests
39-
const accessLogStream = createWriteStream(join(__dirname, '../access.log'), {
39+
const accessLogStream = createWriteStream(join(__dirname, 'access.log'), {
4040
flags: 'a'
4141
})
4242
app.use(

src/database/hello-world.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"status": "success",
3+
"message": "Hello World API!",
4+
"products": [
5+
{
6+
"id": "1",
7+
"name": "MacBook Pro"
8+
},
9+
{
10+
"id": "2",
11+
"name": "HP"
12+
},
13+
{
14+
"id": "3",
15+
"name": "Dell"
16+
}
17+
]
18+
}

src/routes/api/v1/hello-world.ts

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,11 @@
11
import type { Request, Response } from 'express'
22
import express from 'express'
3+
import apiResponse from '../../../database/hello-world.json'
34
import authentication from '../../../middleware/security/authentication'
45

56
const router = express.Router()
67

78
router.get('/', authentication, (_request: Request, response: Response) => {
8-
response.json({
9-
status: 'success',
10-
message: 'Hello World API!',
11-
products: [
12-
{
13-
id: '1',
14-
name: 'MacBook Pro'
15-
},
16-
{
17-
id: '2',
18-
name: 'HP'
19-
},
20-
{
21-
id: '3',
22-
name: 'Dell'
23-
}
24-
]
25-
})
9+
response.json(apiResponse)
2610
})
2711
export default router

0 commit comments

Comments
 (0)