Add healthcheck endpoints and scripts
This commit is contained in:
@ -0,0 +1,36 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
port, exists := os.LookupEnv("PORT")
|
||||
if !exists {
|
||||
port = "8080"
|
||||
}
|
||||
|
||||
client := http.Client{
|
||||
Timeout: 2 * time.Second,
|
||||
}
|
||||
|
||||
resp, err := client.Get("http://localhost:" + port + "/ping")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Print the HTTP Status Code and Status Name
|
||||
fmt.Println("HTTP Response Status:", resp.StatusCode, http.StatusText(resp.StatusCode))
|
||||
|
||||
if resp.StatusCode >= 200 && resp.StatusCode <= 299 {
|
||||
fmt.Println("HTTP Status is in the 2xx range")
|
||||
} else {
|
||||
fmt.Println("Argh! Broken")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@ -42,5 +42,11 @@ func main() {
|
||||
"now": tm,
|
||||
})
|
||||
})
|
||||
r.Run() // listen and serve on 0.0.0.0:8080
|
||||
|
||||
r.GET("/ping", func(c *gin.Context) {
|
||||
tm = database.GetTime(c)
|
||||
c.JSON(200, "pong")
|
||||
})
|
||||
|
||||
r.Run() // listen and serve on 0.0.0.0:8080 (or "PORT" env var)
|
||||
}
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
var http = require('http');
|
||||
|
||||
var options = {
|
||||
timeout: 2000,
|
||||
host: 'localhost',
|
||||
port: process.env.PORT || 3000,
|
||||
path: '/ping',
|
||||
};
|
||||
|
||||
var request = http.request(options, (res) => {
|
||||
console.info('STATUS: ' + res.statusCode);
|
||||
process.exitCode = res.statusCode === 200 ? 0 : 1;
|
||||
process.exit();
|
||||
});
|
||||
|
||||
request.on('error', function (err) {
|
||||
console.error('ERROR', err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
request.end();
|
||||
@ -4,7 +4,7 @@ const express = require('express');
|
||||
const morgan = require('morgan');
|
||||
|
||||
const app = express();
|
||||
const port = 3000;
|
||||
const port = process.env.PORT || 3000;
|
||||
|
||||
// setup the logger
|
||||
app.use(morgan('tiny'));
|
||||
@ -16,6 +16,10 @@ app.get('/', async (req, res) => {
|
||||
res.send(response);
|
||||
});
|
||||
|
||||
app.get('/ping', async (_, res) => {
|
||||
res.send('pong');
|
||||
});
|
||||
|
||||
const server = app.listen(port, () => {
|
||||
console.log(`Example app listening on port ${port}`);
|
||||
});
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
server {
|
||||
listen 80;
|
||||
location /ping {
|
||||
access_log off;
|
||||
add_header 'Content-Type' 'text/plain';
|
||||
return 200 "pong";
|
||||
}
|
||||
location /api/golang/ {
|
||||
resolver 127.0.0.1;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
|
||||
58
06-building-container-images/api-golang/Dockerfile.7
Normal file
58
06-building-container-images/api-golang/Dockerfile.7
Normal file
@ -0,0 +1,58 @@
|
||||
# Pin specific version for stability
|
||||
# Use separate stage for building image
|
||||
# Use debian for easier build utilities
|
||||
FROM golang:1.19-bullseye AS build
|
||||
|
||||
# Add non root user
|
||||
RUN useradd -u 1001 nonroot
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy only files required to install dependencies (better layer caching)
|
||||
COPY go.mod go.sum ./
|
||||
|
||||
# Use cache mount to speed up install of existing dependencies
|
||||
RUN --mount=type=cache,target=/go/pkg/mod \
|
||||
--mount=type=cache,target=/root/.cache/go-build \
|
||||
go mod download
|
||||
|
||||
COPY . .
|
||||
|
||||
# Compile healthcheck
|
||||
RUN go build \
|
||||
-ldflags="-linkmode external -extldflags -static" \
|
||||
-tags netgo \
|
||||
-o healthcheck \
|
||||
./healthcheck/healthcheck.go
|
||||
|
||||
# Compile application during build rather than at runtime
|
||||
# Add flags to statically link binary
|
||||
RUN go build \
|
||||
-ldflags="-linkmode external -extldflags -static" \
|
||||
-tags netgo \
|
||||
-o api-golang
|
||||
|
||||
# Use separate stage for deployable image
|
||||
FROM scratch
|
||||
|
||||
# Set gin mode
|
||||
ENV GIN_MODE=release
|
||||
|
||||
WORKDIR /
|
||||
|
||||
# Copy the passwd file
|
||||
COPY --from=build /etc/passwd /etc/passwd
|
||||
|
||||
# Copy the healthcheck binary from the build stage
|
||||
COPY --from=build /app/healthcheck/healthcheck healthcheck
|
||||
|
||||
# Copy the app binary from the build stage
|
||||
COPY --from=build /app/api-golang api-golang
|
||||
|
||||
# Use nonroot user
|
||||
USER nonroot
|
||||
|
||||
# Indicate expected port
|
||||
EXPOSE 8080
|
||||
|
||||
CMD ["/api-golang"]
|
||||
@ -11,7 +11,7 @@ build-N:
|
||||
|
||||
.PHONY: build-all
|
||||
build-all:
|
||||
for number in 0 1 2 3 4 5 6 ; do \
|
||||
for number in 0 1 2 3 4 5 6 7; do \
|
||||
N=$$number $(MAKE) build-N; \
|
||||
done
|
||||
|
||||
@ -21,6 +21,6 @@ push-N:
|
||||
|
||||
.PHONY: push-all
|
||||
push-all:
|
||||
for number in 0 1 2 3 4 5 6 ; do \
|
||||
for number in 0 1 2 3 4 5 6 7; do \
|
||||
N=$$number $(MAKE) push-N; \
|
||||
done
|
||||
|
||||
39
06-building-container-images/api-node/Dockerfile.8
Normal file
39
06-building-container-images/api-node/Dockerfile.8
Normal file
@ -0,0 +1,39 @@
|
||||
# Pin specific version for stability
|
||||
# Use alpine for reduced image size
|
||||
FROM node:19.4-alpine
|
||||
|
||||
# Set NODE_ENV
|
||||
ENV NODE_ENV production
|
||||
|
||||
# Specify working directory other than /
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# Copy only files required to install
|
||||
# dependencies (better layer caching)
|
||||
COPY package*.json ./
|
||||
|
||||
# Install only production dependencies
|
||||
# Use cache mount to speed up install of existing dependencies
|
||||
RUN --mount=type=cache,target=/usr/src/app/.npm \
|
||||
npm set cache /usr/src/app/.npm && \
|
||||
npm ci --only=production
|
||||
|
||||
# Use non-root user
|
||||
# Use --chown on COPY commands to set file permissions
|
||||
USER node
|
||||
|
||||
# Copy the healthcheck script
|
||||
COPY --chown=node:node ./healthcheck/ .
|
||||
|
||||
# Copy remaining source code AFTER installing dependencies.
|
||||
# Again, copy only the necessary files
|
||||
COPY --chown=node:node ./src/ .
|
||||
|
||||
# Indicate expected port
|
||||
EXPOSE 3000
|
||||
|
||||
CMD [ "node", "index.js" ]
|
||||
|
||||
# TODO: Use multi-stage with distroless image or chainguard image?
|
||||
# https://github.com/GoogleContainerTools/distroless/blob/main/examples/nodejs/Dockerfile
|
||||
# https://edu.chainguard.dev/chainguard/chainguard-images/reference/node/overview/
|
||||
@ -11,7 +11,7 @@ build-N:
|
||||
|
||||
.PHONY: build-all
|
||||
build-all:
|
||||
for number in 0 1 2 3 4 5 6 7 ; do \
|
||||
for number in 0 1 2 3 4 5 6 7 8; do \
|
||||
N=$$number $(MAKE) build-N; \
|
||||
done
|
||||
|
||||
@ -21,6 +21,6 @@ push-N:
|
||||
|
||||
.PHONY: push-all
|
||||
push-all:
|
||||
for number in 0 1 2 3 4 5 6 7; do \
|
||||
for number in 0 1 2 3 4 5 6 7 8; do \
|
||||
N=$$number $(MAKE) push-N; \
|
||||
done
|
||||
@ -10,7 +10,7 @@ services:
|
||||
api-node:
|
||||
build:
|
||||
context: ../05-example-web-application/api-node/
|
||||
dockerfile: ../../06-building-container-images/api-node/Dockerfile.7
|
||||
dockerfile: ../../06-building-container-images/api-node/Dockerfile.8
|
||||
init: true
|
||||
depends_on:
|
||||
- db
|
||||
|
||||
@ -7,8 +7,10 @@ services:
|
||||
- 5173:5173
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ../05-example-web-application/client-react/src
|
||||
target: /usr/src/app/src
|
||||
source: ../05-example-web-application/client-react/
|
||||
target: /usr/src/app/
|
||||
- type: volume
|
||||
target: /usr/src/app/node_modules
|
||||
- type: bind
|
||||
source: ../08-running-containers/client-react/vite.config.js
|
||||
target: /usr/src/app/vite.config.js
|
||||
@ -20,8 +22,10 @@ services:
|
||||
target: dev
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ../05-example-web-application/api-node/src/
|
||||
target: /usr/src/app/src/
|
||||
source: ../05-example-web-application/api-node/
|
||||
target: /usr/src/app/
|
||||
- type: volume
|
||||
target: /usr/src/app/node_modules
|
||||
init: true
|
||||
depends_on:
|
||||
- db
|
||||
|
||||
@ -9,19 +9,21 @@ compose-up-d:
|
||||
|
||||
###
|
||||
|
||||
CIVO_SSH:="ssh://ubuntu@212.2.244.220"
|
||||
|
||||
.PHONY: swarm-init
|
||||
swarm-init:
|
||||
docker swarm init
|
||||
DOCKER_HOST=${CIVO_SSH} docker swarm init
|
||||
|
||||
.PHONY: swarm-deploy-stack
|
||||
swarm-deploy-stack:
|
||||
docker stack deploy -c stack.yaml example-app
|
||||
DOCKER_HOST=${CIVO_SSH} docker stack deploy -c docker-swarm.yml example-app
|
||||
|
||||
.PHONY: swarm-remove-stack
|
||||
swarm-remove-stack:
|
||||
docker stack rm example-app
|
||||
DOCKER_HOST=${CIVO_SSH} docker stack rm example-app
|
||||
|
||||
.PHONY: create-secrets
|
||||
create-secrets:
|
||||
echo -n "foobarbaz" | docker secret create postgres-passwd -
|
||||
echo -n "postgres://postgres:foobarbaz@db:5432/postgres" | docker secret create database-url -
|
||||
echo -n "foobarbaz" | DOCKER_HOST=${CIVO_SSH} docker secret create postgres-passwd -
|
||||
echo -n "postgres://postgres:foobarbaz@db:5432/postgres" | DOCKER_HOST=${CIVO_SSH} docker secret create database-url -
|
||||
@ -7,8 +7,14 @@ services:
|
||||
ports:
|
||||
- 80:80
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost/ping"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
api-node:
|
||||
image: sidpalas/devops-directive-docker-course-api-node:7
|
||||
image: sidpalas/devops-directive-docker-course-api-node:8
|
||||
networks:
|
||||
- frontend
|
||||
- backend
|
||||
@ -18,8 +24,14 @@ services:
|
||||
environment:
|
||||
- DATABASE_URL=postgres://postgres:foobarbaz@db:5432/postgres
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "node", "src/healthcheck.js"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
api-golang:
|
||||
image: sidpalas/devops-directive-docker-course-api-golang:6
|
||||
image: sidpalas/devops-directive-docker-course-api-golang:7
|
||||
networks:
|
||||
- frontend
|
||||
- backend
|
||||
@ -29,6 +41,12 @@ services:
|
||||
environment:
|
||||
- DATABASE_URL=postgres://postgres:foobarbaz@db:5432/postgres
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "/healthcheck"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
db:
|
||||
image: postgres:15.1-alpine
|
||||
networks:
|
||||
@ -37,6 +55,11 @@ services:
|
||||
- pgdata:/var/lib/postgresql/data
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=foobarbaz
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
|
||||
@ -7,8 +7,14 @@ services:
|
||||
- frontend
|
||||
ports:
|
||||
- 80:80
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost/ping"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
api-node:
|
||||
image: sidpalas/devops-directive-docker-course-api-node:7
|
||||
image: sidpalas/devops-directive-docker-course-api-node:8
|
||||
environment:
|
||||
- DATABASE_URL_FILE=/run/secrets/database-url
|
||||
secrets:
|
||||
@ -18,8 +24,14 @@ services:
|
||||
- backend
|
||||
ports:
|
||||
- 3000:3000
|
||||
healthcheck:
|
||||
test: ["CMD", "node", "/usr/src/app/healthcheck.js"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
api-golang:
|
||||
image: sidpalas/devops-directive-docker-course-api-golang:6
|
||||
image: sidpalas/devops-directive-docker-course-api-golang:7
|
||||
networks:
|
||||
- frontend
|
||||
- backend
|
||||
@ -29,6 +41,12 @@ services:
|
||||
- database-url
|
||||
ports:
|
||||
- 8080:8080
|
||||
healthcheck:
|
||||
test: ["CMD", "/healthcheck"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
db:
|
||||
image: postgres:15.1-alpine
|
||||
networks:
|
||||
@ -41,6 +59,11 @@ services:
|
||||
- POSTGRES_PASSWORD_FILE=/run/secrets/postgres-passwd
|
||||
secrets:
|
||||
- postgres-passwd
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
|
||||
Reference in New Issue
Block a user