From a601356d673190b56b4bc32da594b07099006c3d Mon Sep 17 00:00:00 2001 From: Jotham Arinze Date: Mon, 24 Feb 2025 22:09:03 +0100 Subject: [PATCH 1/3] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 678eb616..b369fae4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# HNG12 DevOps Stage3 Task +# HNG12 DevOps Stage4 Task This Repo Contains the code for a microservice application comprising of several components communicating to each other. In other words, this is an example of microservice. These microservices are written in different languages. From 30d81c2f028a9f0f6143933aaaed1a54d8b52080 Mon Sep 17 00:00:00 2001 From: oyedeji samuel Date: Wed, 26 Feb 2025 16:11:37 +0100 Subject: [PATCH 2/3] added dockerfiles and docker-compose file --- acme.json | 0 auth-api/Dockerfile | 9 +++++ docker-compose.yml | 67 ++++++++++++++++++++++++++++++++ frontend/Dockerfile | 12 ++++++ log-message-processor/Dockerfile | 7 ++++ todos-api/Dockerfile | 8 ++++ traefik.yml | 21 ++++++++++ users-api/Dockerfile | 6 +++ 8 files changed, 130 insertions(+) create mode 100644 acme.json create mode 100644 auth-api/Dockerfile create mode 100644 docker-compose.yml create mode 100644 frontend/Dockerfile create mode 100644 log-message-processor/Dockerfile create mode 100644 todos-api/Dockerfile create mode 100644 traefik.yml create mode 100644 users-api/Dockerfile diff --git a/acme.json b/acme.json new file mode 100644 index 00000000..e69de29b diff --git a/auth-api/Dockerfile b/auth-api/Dockerfile new file mode 100644 index 00000000..17c8ced2 --- /dev/null +++ b/auth-api/Dockerfile @@ -0,0 +1,9 @@ +# Dockerfile for Go Auth API +FROM golang:1.20-alpine +WORKDIR /app +COPY go.mod go.sum ./ +RUN go mod download +COPY . . +RUN go build -o main . +EXPOSE 8080 +CMD ["./main"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..c2dfc252 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3.8" + +services: + traefik: + image: "traefik:v2.10" + container_name: "traefik" + restart: always + command: + - "--api.insecure=true" + - "--providers.docker=true" + - "--entrypoints.web.address=:80" + - "--entrypoints.websecure.address=:443" + - "--certificatesresolvers.myresolver.acme.httpChallenge.entryPoint=web" + - "--certificatesresolvers.myresolver.acme.email=oyedejisamuel05@gmail.com" + - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json" + ports: + - "80:80" + - "443:443" + volumes: + - "/var/run/docker.sock:/var/run/docker.sock" + - "./letsencrypt:/letsencrypt" + + frontend: + build: ./frontend + labels: + - "traefik.enable=true" + - "traefik.http.routers.frontend.rule=Host(`samops.name.ng`)" + - "traefik.http.routers.frontend.entrypoints=websecure" + - "traefik.http.routers.frontend.tls.certresolver=myresolver" + depends_on: + - auth-api + - todos-api + - users-api + + auth-api: + build: ./auth-api + labels: + - "traefik.enable=true" + - "traefik.http.routers.auth.rule=Host(`auth.samops.name.ng`)" + - "traefik.http.routers.auth.entrypoints=websecure" + - "traefik.http.routers.auth.tls.certresolver=myresolver" + + todos-api: + build: ./todos-api + labels: + - "traefik.enable=true" + - "traefik.http.routers.todos.rule=Host(`todos.samops.name.ng`)" + - "traefik.http.routers.todos.entrypoints=websecure" + - "traefik.http.routers.todos.tls.certresolver=myresolver" + + users-api: + build: ./users-api + labels: + - "traefik.enable=true" + - "traefik.http.routers.users.rule=Host(`users.samops.name.ng`)" + - "traefik.http.routers.users.entrypoints=websecure" + - "traefik.http.routers.users.tls.certresolver=myresolver" + + log-processor: + build: ./log-processor + + redis: + image: "redis:alpine" + +networks: + default: + driver: bridge diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 00000000..d3944cca --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,12 @@ +# Dockerfile for Vue.js Frontend +FROM node:18-alpine AS build +WORKDIR /app +COPY package.json package-lock.json ./ +RUN npm install +COPY . . +RUN npm run build + +FROM nginx:alpine +COPY --from=build /app/dist /usr/share/nginx/html +EXPOSE 80 +CMD ["nginx", "-g", "daemon off;"] diff --git a/log-message-processor/Dockerfile b/log-message-processor/Dockerfile new file mode 100644 index 00000000..2eb331ff --- /dev/null +++ b/log-message-processor/Dockerfile @@ -0,0 +1,7 @@ +# Dockerfile for Python Log Message Processor +FROM python:3.10-slim +WORKDIR /app +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt +COPY . . +CMD ["python", "processor.py"] diff --git a/todos-api/Dockerfile b/todos-api/Dockerfile new file mode 100644 index 00000000..1a4c4cc9 --- /dev/null +++ b/todos-api/Dockerfile @@ -0,0 +1,8 @@ +# Dockerfile for Node.js Todos API +FROM node:18-alpine +WORKDIR /app +COPY package.json package-lock.json ./ +RUN npm install +COPY . . +EXPOSE 3000 +CMD ["node", "server.js"] diff --git a/traefik.yml b/traefik.yml new file mode 100644 index 00000000..c8178fc1 --- /dev/null +++ b/traefik.yml @@ -0,0 +1,21 @@ +global: + checkNewVersion: true + sendAnonymousUsage: false + +entryPoints: + web: + address: ":80" + websecure: + address: ":443" + +providers: + docker: + exposedByDefault: false + +certificatesResolvers: + myresolver: + acme: + email: oyedejisamuel05@gmail.com + storage: acme.json + httpChallenge: + entryPoint: web diff --git a/users-api/Dockerfile b/users-api/Dockerfile new file mode 100644 index 00000000..6d18fa1c --- /dev/null +++ b/users-api/Dockerfile @@ -0,0 +1,6 @@ +# Dockerfile for Java Users API +FROM eclipse-temurin:17-jdk-alpine +WORKDIR /app +COPY target/*.jar app.jar +EXPOSE 8081 +CMD ["java", "-jar", "app.jar"] From 38bc99824647acce3932792ff8c08f7009fd9774 Mon Sep 17 00:00:00 2001 From: oyedeji samuel Date: Thu, 27 Feb 2025 11:50:47 +0100 Subject: [PATCH 3/3] more changes --- .env | 6 +- auth-api/Dockerfile | 31 +++++-- docker-compose.yml | 141 ++++++++++++++++++++++++------- frontend/Dockerfile | 32 +++++-- log-message-processor/Dockerfile | 15 ++-- todos-api/Dockerfile | 18 ++-- traefik.yml | 21 ----- users-api/Dockerfile | 31 +++++-- 8 files changed, 211 insertions(+), 84 deletions(-) delete mode 100644 traefik.yml diff --git a/.env b/.env index 0a007615..765165a0 100644 --- a/.env +++ b/.env @@ -25,6 +25,6 @@ REDIS_CHANNEL=log_channel #login details # USERNAME PASSWORD -admin Admin123 -hng HngTech -user Password +#admin Admin123 +#hng HngTech +#user Password diff --git a/auth-api/Dockerfile b/auth-api/Dockerfile index 17c8ced2..f17cbd4e 100644 --- a/auth-api/Dockerfile +++ b/auth-api/Dockerfile @@ -1,9 +1,28 @@ -# Dockerfile for Go Auth API -FROM golang:1.20-alpine +FROM golang:1.20-alpine AS builder + WORKDIR /app -COPY go.mod go.sum ./ + +# Copy go mod and sum files +COPY auth-api/go.mod auth-api/go.sum ./ + +# Download dependencies RUN go mod download -COPY . . -RUN go build -o main . -EXPOSE 8080 + +# Copy source code +COPY auth-api/ . + +# Build the application +RUN CGO_ENABLED=0 GOOS=linux go build -o auth-api . + +# Use a small image for the final stage +FROM alpine:3.17 + +WORKDIR /app + +# Copy the binary from the builder stage +COPY --from=builder /app/auth-api . + +# Expose the port specified in .env +EXPOSE 8081 + CMD ["./main"] diff --git a/docker-compose.yml b/docker-compose.yml index c2dfc252..c2c7952e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,67 +1,148 @@ -version: "3.8" +version: '3.8' services: - traefik: - image: "traefik:v2.10" - container_name: "traefik" - restart: always - command: - - "--api.insecure=true" - - "--providers.docker=true" - - "--entrypoints.web.address=:80" - - "--entrypoints.websecure.address=:443" - - "--certificatesresolvers.myresolver.acme.httpChallenge.entryPoint=web" - - "--certificatesresolvers.myresolver.acme.email=oyedejisamuel05@gmail.com" - - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json" - ports: - - "80:80" - - "443:443" + # Redis service + redis-queue: + image: redis:alpine + networks: + - backend volumes: - - "/var/run/docker.sock:/var/run/docker.sock" - - "./letsencrypt:/letsencrypt" + - redis-data:/data + # Frontend frontend: - build: ./frontend + build: + context: . + dockerfile: frontend/Dockerfile + environment: + - PORT=8080 + - AUTH_API_ADDRESS=http://auth-api:8081 + - TODOS_API_ADDRESS=http://todos-api:8082 labels: - "traefik.enable=true" - "traefik.http.routers.frontend.rule=Host(`samops.name.ng`)" - "traefik.http.routers.frontend.entrypoints=websecure" - "traefik.http.routers.frontend.tls.certresolver=myresolver" + networks: + - frontend depends_on: - auth-api - todos-api - users-api + # Auth API auth-api: - build: ./auth-api + build: + context: . + dockerfile: auth-api/Dockerfile + environment: + - AUTH_API_PORT=8081 + - JWT_SECRET=myfancysecret + - USERS_API_ADDRESS=http://users-api:8083 + ports: + - "8081:8081" labels: - "traefik.enable=true" - - "traefik.http.routers.auth.rule=Host(`auth.samops.name.ng`)" + - "traefik.http.routers.auth.rule=Host(`auth.samops.name.ng`) || (Host(`samops.name.ng`) && PathPrefix(`/api/auth`))" - "traefik.http.routers.auth.entrypoints=websecure" - "traefik.http.routers.auth.tls.certresolver=myresolver" + - "traefik.http.middlewares.auth-stripprefix.stripprefix.prefixes=/api/auth" + - "traefik.http.routers.auth.middlewares=auth-stripprefix@docker" + networks: + - frontend + - backend + depends_on: + - users-api + # Todos API todos-api: - build: ./todos-api + build: + context: . + dockerfile: todos-api/Dockerfile + environment: + - JWT_SECRET=myfancysecret + - REDIS_HOST=redis-queue + - REDIS_PORT=6379 + - REDIS_CHANNEL=log_channel + ports: + - "8082:8082" labels: - "traefik.enable=true" - - "traefik.http.routers.todos.rule=Host(`todos.samops.name.ng`)" + - "traefik.http.routers.todos.rule=Host(`todos.samops.name.ng`) || (Host(`samops.name.ng`) && PathPrefix(`/api/todos`))" - "traefik.http.routers.todos.entrypoints=websecure" - "traefik.http.routers.todos.tls.certresolver=myresolver" + - "traefik.http.middlewares.todos-stripprefix.stripprefix.prefixes=/api/todos" + - "traefik.http.routers.todos.middlewares=todos-stripprefix@docker" + networks: + - frontend + - backend + depends_on: + - redis-queue + - auth-api + # Users API users-api: - build: ./users-api + build: + context: . + dockerfile: users-api/Dockerfile + environment: + - SERVER_PORT=8083 + - JWT_SECRET=myfancysecret + ports: + - "8083:8083" labels: - "traefik.enable=true" - - "traefik.http.routers.users.rule=Host(`users.samops.name.ng`)" + - "traefik.http.routers.users.rule=Host(`users.samops.name.ng`) || (Host(`samops.name.ng`) && PathPrefix(`/api/users`))" - "traefik.http.routers.users.entrypoints=websecure" - "traefik.http.routers.users.tls.certresolver=myresolver" + - "traefik.http.middlewares.users-stripprefix.stripprefix.prefixes=/api/users" + - "traefik.http.routers.users.middlewares=users-stripprefix@docker" + networks: + - frontend + - backend + # Log Message Processor log-processor: - build: ./log-processor + build: + context: . + dockerfile: log-message-processor/Dockerfile + environment: + - REDIS_HOST=redis-queue + - REDIS_PORT=6379 + - REDIS_CHANNEL=log_channel + networks: + - backend + depends_on: + - redis-queue - redis: - image: "redis:alpine" + # Traefik as reverse proxy with SSL + traefik: + image: traefik:v2.9 + command: + - "--api.insecure=false" + - "--providers.docker=true" + - "--providers.docker.exposedbydefault=false" + - "--entrypoints.web.address=:80" + - "--entrypoints.websecure.address=:443" + - "--certificatesresolvers.myresolver.acme.tlschallenge=true" + - "--certificatesresolvers.myresolver.acme.email=oyedejisamuel05@gmail.com" + - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json" + # Redirect HTTP to HTTPS + - "--entrypoints.web.http.redirections.entryPoint.to=websecure" + - "--entrypoints.web.http.redirections.entryPoint.scheme=https" + ports: + - "80:80" + - "443:443" + volumes: + - "/var/run/docker.sock:/var/run/docker.sock:ro" + - "./letsencrypt:/letsencrypt" + networks: + - frontend + restart: always networks: - default: - driver: bridge + frontend: + backend: + +volumes: + redis-data: \ No newline at end of file diff --git a/frontend/Dockerfile b/frontend/Dockerfile index d3944cca..d19490d9 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,12 +1,28 @@ -# Dockerfile for Vue.js Frontend -FROM node:18-alpine AS build +FROM node:12 as build-stage + WORKDIR /app -COPY package.json package-lock.json ./ + +# Copy package files and install dependencies +COPY frontend/package*.json ./ RUN npm install -COPY . . + +# Copy project files and build +COPY frontend/ . RUN npm run build -FROM nginx:alpine -COPY --from=build /app/dist /usr/share/nginx/html -EXPOSE 80 -CMD ["nginx", "-g", "daemon off;"] +# Production stage +FROM nginx:stable-alpine as production-stage +COPY --from=build-stage /app/dist /usr/share/nginx/html + +# Copy custom nginx configuration +COPY frontend/nginx.conf /etc/nginx/conf.d/default.conf + +EXPOSE 8080 + +# Create a custom entrypoint script to run nginx on the specified port +RUN echo '#!/bin/sh\n\ +sed -i "s/listen 80/listen $PORT/g" /etc/nginx/conf.d/default.conf\n\ +nginx -g "daemon off;"' > /docker-entrypoint.sh && \ +chmod +x /docker-entrypoint.sh + +CMD ["/docker-entrypoint.sh"] \ No newline at end of file diff --git a/log-message-processor/Dockerfile b/log-message-processor/Dockerfile index 2eb331ff..c1e0d968 100644 --- a/log-message-processor/Dockerfile +++ b/log-message-processor/Dockerfile @@ -1,7 +1,12 @@ -# Dockerfile for Python Log Message Processor -FROM python:3.10-slim +FROM python:3.9-slim + WORKDIR /app -COPY requirements.txt . + +# Copy requirements file and install dependencies +COPY log-message-processor/requirements.txt . RUN pip install --no-cache-dir -r requirements.txt -COPY . . -CMD ["python", "processor.py"] + +# Copy project files +COPY log-message-processor/ . + +CMD ["python", "main.py"] \ No newline at end of file diff --git a/todos-api/Dockerfile b/todos-api/Dockerfile index 1a4c4cc9..54030a6e 100644 --- a/todos-api/Dockerfile +++ b/todos-api/Dockerfile @@ -1,8 +1,14 @@ -# Dockerfile for Node.js Todos API -FROM node:18-alpine +FROM node:12 + WORKDIR /app -COPY package.json package-lock.json ./ + +# Copy package files and install dependencies +COPY package*.json ./ RUN npm install -COPY . . -EXPOSE 3000 -CMD ["node", "server.js"] + +# Copy project files +COPY todos-api/ . + +EXPOSE 8082 + +CMD ["npm", "server.js"] \ No newline at end of file diff --git a/traefik.yml b/traefik.yml deleted file mode 100644 index c8178fc1..00000000 --- a/traefik.yml +++ /dev/null @@ -1,21 +0,0 @@ -global: - checkNewVersion: true - sendAnonymousUsage: false - -entryPoints: - web: - address: ":80" - websecure: - address: ":443" - -providers: - docker: - exposedByDefault: false - -certificatesResolvers: - myresolver: - acme: - email: oyedejisamuel05@gmail.com - storage: acme.json - httpChallenge: - entryPoint: web diff --git a/users-api/Dockerfile b/users-api/Dockerfile index 6d18fa1c..ef2d68e2 100644 --- a/users-api/Dockerfile +++ b/users-api/Dockerfile @@ -1,6 +1,27 @@ -# Dockerfile for Java Users API -FROM eclipse-temurin:17-jdk-alpine +FROM maven:3.8.6-openjdk-11 AS build + WORKDIR /app -COPY target/*.jar app.jar -EXPOSE 8081 -CMD ["java", "-jar", "app.jar"] + +# Copy pom.xml +COPY users-api/pom.xml . + +# Download dependencies (this layer can be cached) +RUN mvn dependency:go-offline -B + +# Copy source code +COPY users-api/src ./src + +# Build the application +RUN mvn package -DskipTests + +# Final stage +FROM openjdk:11-jre-slim + +WORKDIR /app + +# Copy JAR from build stage +COPY --from=build /app/target/*.jar app.jar + +EXPOSE 8083 + +CMD ["java", "-jar", "app.jar"] \ No newline at end of file