mirror of
https://gitlab.dit.htwk-leipzig.de/htwk-software/htwkalender-pwa.git
synced 2025-07-16 17:48:51 +02:00
Add deployment and improve Dockerfiles and CICD
This commit is contained in:
@ -2,7 +2,8 @@ stages:
|
|||||||
- lint
|
- lint
|
||||||
- build
|
- build
|
||||||
- test
|
- test
|
||||||
- docker
|
- oci-build
|
||||||
|
- deploy
|
||||||
|
|
||||||
lint-frontend:
|
lint-frontend:
|
||||||
image: node:lts
|
image: node:lts
|
||||||
@ -29,7 +30,7 @@ lint-backend:
|
|||||||
|
|
||||||
|
|
||||||
build-backend:
|
build-backend:
|
||||||
image: golang:1.21-alpine
|
image: golang:alpine
|
||||||
stage: build
|
stage: build
|
||||||
rules:
|
rules:
|
||||||
- changes:
|
- changes:
|
||||||
@ -58,7 +59,7 @@ build-frontend:
|
|||||||
- frontend/build
|
- frontend/build
|
||||||
|
|
||||||
test-backend:
|
test-backend:
|
||||||
image: golang:1.21-alpine
|
image: golang:alpine
|
||||||
stage: test
|
stage: test
|
||||||
rules:
|
rules:
|
||||||
- changes:
|
- changes:
|
||||||
@ -83,11 +84,10 @@ test-frontend:
|
|||||||
- lint-frontend
|
- lint-frontend
|
||||||
|
|
||||||
build-backend-image:
|
build-backend-image:
|
||||||
stage: docker
|
stage: oci-build
|
||||||
image: docker:20.10.16
|
image: docker:latest
|
||||||
services:
|
services:
|
||||||
- name: docker:20.10.16-dind
|
- docker:dind
|
||||||
alias: docker
|
|
||||||
tags:
|
tags:
|
||||||
- image
|
- image
|
||||||
variables:
|
variables:
|
||||||
@ -96,22 +96,19 @@ build-backend-image:
|
|||||||
DOCKER_TLS_CERTDIR: "/certs"
|
DOCKER_TLS_CERTDIR: "/certs"
|
||||||
DOCKER_TLS_VERIFY: 1
|
DOCKER_TLS_VERIFY: 1
|
||||||
DOCKER_CERT_PATH: "/certs/client"
|
DOCKER_CERT_PATH: "/certs/client"
|
||||||
script:
|
before_script:
|
||||||
- cd backend
|
|
||||||
- docker login -u $CI_DOCKER_REGISTRY_USER -p $CI_DOCKER_REGISTRY_PASSWORD $CI_DOCKER_REGISTRY
|
- docker login -u $CI_DOCKER_REGISTRY_USER -p $CI_DOCKER_REGISTRY_PASSWORD $CI_DOCKER_REGISTRY
|
||||||
- docker build -t htwkalender-backend$IMAGE_TAG .
|
script:
|
||||||
- docker tag htwkalender-backend$IMAGE_TAG $CI_DOCKER_REGISTRY_USER/htwkalender:backend
|
- docker build --pull -t $CI_DOCKER_REGISTRY_REPO:backend -f ./backend/Dockerfile --target prod ./backend
|
||||||
- docker push $CI_DOCKER_REGISTRY_USER/htwkalender:backend
|
- docker push $CI_DOCKER_REGISTRY_REPO:backend
|
||||||
only:
|
rules:
|
||||||
- main
|
- if: $CI_COMMIT_BRANCH == "main"
|
||||||
- development
|
|
||||||
|
|
||||||
build-frontend-image:
|
build-frontend-image:
|
||||||
stage: docker
|
stage: oci-build
|
||||||
image: docker:20.10.16
|
image: docker:latest
|
||||||
services:
|
services:
|
||||||
- name: docker:20.10.16-dind
|
- docker:dind
|
||||||
alias: docker
|
|
||||||
tags:
|
tags:
|
||||||
- image
|
- image
|
||||||
variables:
|
variables:
|
||||||
@ -120,12 +117,36 @@ build-frontend-image:
|
|||||||
DOCKER_TLS_CERTDIR: "/certs"
|
DOCKER_TLS_CERTDIR: "/certs"
|
||||||
DOCKER_TLS_VERIFY: 1
|
DOCKER_TLS_VERIFY: 1
|
||||||
DOCKER_CERT_PATH: "/certs/client"
|
DOCKER_CERT_PATH: "/certs/client"
|
||||||
script:
|
before_script:
|
||||||
- cd frontend
|
|
||||||
- docker login -u $CI_DOCKER_REGISTRY_USER -p $CI_DOCKER_REGISTRY_PASSWORD $CI_DOCKER_REGISTRY
|
- docker login -u $CI_DOCKER_REGISTRY_USER -p $CI_DOCKER_REGISTRY_PASSWORD $CI_DOCKER_REGISTRY
|
||||||
- docker build -f Dockerfile_prod -t htwkalender-frontend$IMAGE_TAG .
|
script:
|
||||||
- docker tag htwkalender-frontend$IMAGE_TAG $CI_DOCKER_REGISTRY_USER/htwkalender:frontend
|
- docker build --pull -t $CI_DOCKER_REGISTRY_REPO:frontend -f ./frontend/Dockerfile --target prod .
|
||||||
- docker push $CI_DOCKER_REGISTRY_USER/htwkalender:frontend
|
- docker push $CI_DOCKER_REGISTRY_REPO:frontend
|
||||||
only:
|
rules:
|
||||||
- main
|
- if: $CI_COMMIT_BRANCH == "main"
|
||||||
- development
|
|
||||||
|
deploy-all:
|
||||||
|
stage: deploy
|
||||||
|
image: alpine:latest
|
||||||
|
before_script:
|
||||||
|
- apk add --no-cache openssh-client sed # install dependencies
|
||||||
|
- eval $(ssh-agent -s) # set some ssh variables
|
||||||
|
- ssh-add <(echo "$CI_SSH_KEY" | tr -d '\r')
|
||||||
|
script:
|
||||||
|
# replace some placeholders
|
||||||
|
- sed -i -e "s|DOCKER_REGISTRY_REPO|$CI_DOCKER_REGISTRY_REPO|" docker-compose.prod.yml
|
||||||
|
# upload necessary files to the server
|
||||||
|
- >
|
||||||
|
scp -P $CI_SSH_PORT -o StrictHostKeyChecking=no -o LogLevel=ERROR ./docker-compose.prod.yml ./reverseproxy.conf
|
||||||
|
$CI_SSH_USER@$CI_SSH_HOST:/home/$CI_SSH_USER/docker/htwkalender/
|
||||||
|
# ssh to the server and start the service
|
||||||
|
- >
|
||||||
|
ssh -p $CI_SSH_PORT -o StrictHostKeyChecking=no -o LogLevel=ERROR $CI_SSH_USER@$CI_SSH_HOST
|
||||||
|
"cd /home/$CI_SSH_USER/docker/htwkalender/ &&
|
||||||
|
docker login -u $CI_DOCKER_REGISTRY_USER -p $CI_DOCKER_REGISTRY_PASSWORD $CI_DOCKER_REGISTRY &&
|
||||||
|
docker compose -f ./docker-compose.prod.yml down && docker compose -f ./docker-compose.prod.yml up -d --remove-orphans && docker logout"
|
||||||
|
needs:
|
||||||
|
- build-frontend-image
|
||||||
|
- build-backend-image
|
||||||
|
rules:
|
||||||
|
- if: $CI_COMMIT_BRANCH == "main"
|
||||||
|
@ -1,18 +1,31 @@
|
|||||||
FROM golang:1.21.6
|
# build stage
|
||||||
|
FROM golang:alpine AS build
|
||||||
|
|
||||||
# Set the Current Working Directory inside the container
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Copy go mod and sum files
|
|
||||||
COPY go.mod go.sum ./
|
|
||||||
RUN go mod download
|
|
||||||
|
|
||||||
# Copy the source from the current directory to the Working Directory inside the container
|
# Copy the source from the current directory to the Working Directory inside the container
|
||||||
COPY *.go ./
|
COPY . ./
|
||||||
COPY . .
|
# download needed modules
|
||||||
|
RUN apk add --no-cache --update go gcc g++ && \
|
||||||
|
go mod download && \
|
||||||
|
CGO_ENABLED=1 GOOS=linux go build -o /htwkalender
|
||||||
|
|
||||||
# Build the Go app
|
# production stage
|
||||||
RUN CGO_ENABLED=1 GOOS=linux go build -o /htwkalender
|
FROM alpine:latest AS prod
|
||||||
|
|
||||||
# Expose port 8080 to the outside world
|
WORKDIR /htwkalender
|
||||||
EXPOSE 8080
|
|
||||||
|
ARG USER=ical
|
||||||
|
RUN adduser -Ds /bin/sh $USER && \
|
||||||
|
chown $USER:$USER ./
|
||||||
|
|
||||||
|
USER $USER
|
||||||
|
RUN mkdir -p data
|
||||||
|
|
||||||
|
# copies executable from build container
|
||||||
|
COPY --chown=$USER:$USER --from=build /htwkalender ./
|
||||||
|
|
||||||
|
# Expose port 8090 to the outside world
|
||||||
|
EXPOSE 8090
|
||||||
|
|
||||||
|
ENTRYPOINT ["./htwkalender", "serve"]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
module htwkalender
|
module htwkalender
|
||||||
|
|
||||||
go 1.21
|
go 1.21.6
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/PuerkitoBio/goquery v1.8.1
|
github.com/PuerkitoBio/goquery v1.8.1
|
||||||
|
@ -1,14 +1,22 @@
|
|||||||
package date
|
package date
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log/slog"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
_ "time/tzdata"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetDateFromWeekNumber(year int, weekNumber int, dayName string) (time.Time, error) {
|
func GetDateFromWeekNumber(year int, weekNumber int, dayName string) (time.Time, error) {
|
||||||
// Create a time.Date for the first day of the year
|
// Create a time.Date for the first day of the year
|
||||||
europeTime, _ := time.LoadLocation("Europe/Berlin")
|
europeTime, err := time.LoadLocation("Europe/Berlin")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Failed to load location: ", err)
|
||||||
|
return time.Time{}, err
|
||||||
|
}
|
||||||
|
|
||||||
firstDayOfYear := time.Date(year, time.January, 1, 0, 0, 0, 0, europeTime)
|
firstDayOfYear := time.Date(year, time.January, 1, 0, 0, 0, 0, europeTime)
|
||||||
|
|
||||||
// Calculate the number of days to add to reach the desired week
|
// Calculate the number of days to add to reach the desired week
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
_ "time/tzdata"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_getDateFromWeekNumber(t *testing.T) {
|
func Test_getDateFromWeekNumber(t *testing.T) {
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jordic/goics"
|
"github.com/jordic/goics"
|
||||||
|
_ "time/tzdata"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IcalModel local type for EmitICal function
|
// IcalModel local type for EmitICal function
|
||||||
|
@ -2,25 +2,32 @@ version: "3.9"
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
htwkalender-backend:
|
htwkalender-backend:
|
||||||
build:
|
image: DOCKER_REGISTRY_REPO:backend # DOCKER_REGISTRY_REPO will be replaced by CI
|
||||||
dockerfile: Dockerfile
|
command: "--http=0.0.0.0:8090 --dir=/htwkalender/data/pb_data"
|
||||||
context: ./backend
|
pull_policy: always
|
||||||
# open port 8090
|
# open port 8090
|
||||||
ports:
|
ports:
|
||||||
- "8090:8090"
|
- "8090:8090"
|
||||||
command: "/htwkalender serve --http=0.0.0.0:8090 --dir=/pb_data"
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./backend/pb_data:/pb_data
|
- pb_data:/htwkalender/data
|
||||||
|
|
||||||
htwkalender-frontend:
|
htwkalender-frontend:
|
||||||
build:
|
image: DOCKER_REGISTRY_REPO:frontend # DOCKER_REGISTRY_REPO will be replaced by CI
|
||||||
context: ./frontend
|
pull_policy: always
|
||||||
dockerfile: Dockerfile_prod
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
depends_on:
|
||||||
|
- htwkalender-backend
|
||||||
|
|
||||||
rproxy:
|
rproxy:
|
||||||
image: nginx:stable
|
image: bitnami/nginx:1.25
|
||||||
volumes:
|
volumes:
|
||||||
- ./reverseproxy.conf:/etc/nginx/nginx.conf
|
- ./reverseproxy.conf:/opt/bitnami/nginx/conf/nginx.conf
|
||||||
depends_on:
|
depends_on:
|
||||||
- htwkalender-backend
|
- htwkalender-backend
|
||||||
- htwkalender-frontend
|
- htwkalender-frontend
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
pb_data:
|
||||||
|
@ -5,29 +5,33 @@ services:
|
|||||||
build:
|
build:
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
context: ./backend
|
context: ./backend
|
||||||
|
target: prod
|
||||||
|
command: "--http=0.0.0.0:8090 --dir=/htwkalender/data/pb_data"
|
||||||
# open port 8090
|
# open port 8090
|
||||||
ports:
|
ports:
|
||||||
- "8090:8090"
|
- "8090:8090"
|
||||||
command: "/htwkalender serve --http=0.0.0.0:8090 --dir=/pb_data"
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./backend/pb_data:/pb_data
|
- pb_data:/htwkalender/data
|
||||||
|
|
||||||
htwkalender-frontend:
|
htwkalender-frontend:
|
||||||
volumes:
|
|
||||||
- ./frontend/src:/app/src
|
|
||||||
build:
|
build:
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
context: ./frontend
|
context: ./frontend
|
||||||
|
target: dev
|
||||||
|
command: "npm run dev"
|
||||||
# open port 8000
|
# open port 8000
|
||||||
ports:
|
ports:
|
||||||
- "8000:8000"
|
- "8000:8000"
|
||||||
command: "npm run dev"
|
|
||||||
|
|
||||||
rproxy:
|
rproxy:
|
||||||
image: nginx:stable
|
image: bitnami/nginx:1.25
|
||||||
volumes:
|
volumes:
|
||||||
- ./reverseproxy.conf:/etc/nginx/nginx.conf
|
- ./reverseproxy.conf:/opt/bitnami/nginx/conf/nginx.conf
|
||||||
depends_on:
|
depends_on:
|
||||||
- htwkalender-backend
|
- htwkalender-backend
|
||||||
- htwkalender-frontend
|
- htwkalender-frontend
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
pb_data:
|
||||||
|
@ -1,7 +1,26 @@
|
|||||||
FROM node:lts-alpine3.18
|
# build stage
|
||||||
|
FROM node:lts-alpine AS build
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY frontend/package*.json ./
|
||||||
|
RUN npm ci
|
||||||
|
COPY frontend/ ./
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# development stage
|
||||||
|
FROM node:lts-alpine AS dev
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
RUN npm install
|
RUN npm install
|
||||||
COPY ./ ./
|
COPY . ./
|
||||||
|
|
||||||
|
# production stage
|
||||||
|
# https://hub.docker.com/r/bitnami/nginx -> always run as non-root user
|
||||||
|
FROM bitnami/nginx:1.25 AS prod
|
||||||
|
|
||||||
|
# copy build files from build container
|
||||||
|
COPY --from=build /app/dist /app
|
||||||
|
COPY ./frontend/nginx.conf /opt/bitnami/nginx/conf/nginx.conf
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
# build stage
|
|
||||||
FROM node:lts-alpine3.18 as build-stage
|
|
||||||
WORKDIR /app
|
|
||||||
COPY package*.json ./
|
|
||||||
RUN npm ci
|
|
||||||
COPY . .
|
|
||||||
RUN npm run build
|
|
||||||
|
|
||||||
# production stage
|
|
||||||
FROM nginx:stable as production-stage
|
|
||||||
COPY --from=build-stage /app/dist /usr/share/nginx/html
|
|
||||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
|
||||||
EXPOSE 8000
|
|
||||||
CMD ["nginx", "-g", "daemon off;"]
|
|
@ -1,47 +1,44 @@
|
|||||||
server {
|
worker_processes 4;
|
||||||
listen 8000;
|
|
||||||
listen [::]:8000;
|
|
||||||
server_name localhost;
|
|
||||||
|
|
||||||
#access_log /var/log/nginx/host.access.log main;
|
error_log /opt/bitnami/nginx/logs/error.log;
|
||||||
|
pid /opt/bitnami/nginx/tmp/nginx.pid;
|
||||||
|
|
||||||
location / {
|
events {
|
||||||
root /usr/share/nginx/html;
|
worker_connections 1024;
|
||||||
index index.html index.htm;
|
}
|
||||||
|
|
||||||
#necessary to display vue subpage
|
http {
|
||||||
try_files $uri $uri/ /index.html;
|
include mime.types;
|
||||||
}
|
default_type application/octet-stream;
|
||||||
|
|
||||||
#error_page 404 /404.html;
|
access_log /opt/bitnami/nginx/logs/proxy_access.log;
|
||||||
|
error_log /opt/bitnami/nginx/logs/proxy_error.log;
|
||||||
# redirect server error pages to the static page /50x.html
|
|
||||||
#
|
sendfile on;
|
||||||
error_page 500 502 503 504 /50x.html;
|
keepalive_timeout 180s;
|
||||||
location = /50x.html {
|
send_timeout 180s;
|
||||||
root /usr/share/nginx/html;
|
|
||||||
}
|
client_body_temp_path /opt/bitnami/nginx/tmp/client_temp;
|
||||||
|
proxy_temp_path /opt/bitnami/nginx/tmp/proxy_temp_path;
|
||||||
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
|
fastcgi_temp_path /opt/bitnami/nginx/tmp/fastcgi_temp;
|
||||||
#
|
uwsgi_temp_path /opt/bitnami/nginx/tmp/uwsgi_temp;
|
||||||
#location ~ \.php$ {
|
scgi_temp_path /opt/bitnami/nginx/tmp/scgi_temp;
|
||||||
# proxy_pass http://127.0.0.1;
|
|
||||||
#}
|
server {
|
||||||
|
listen 8000;
|
||||||
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
|
listen [::]:8000;
|
||||||
#
|
server_name localhost;
|
||||||
#location ~ \.php$ {
|
|
||||||
# root html;
|
location / {
|
||||||
# fastcgi_pass 127.0.0.1:9000;
|
root /opt/bitnami/nginx/html;
|
||||||
# fastcgi_index index.php;
|
index index.html index.htm;
|
||||||
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
|
|
||||||
# include fastcgi_params;
|
#necessary to display vue subpage
|
||||||
#}
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
# deny access to .htaccess files, if Apache's document root
|
error_page 500 502 503 504 /50x.html;
|
||||||
# concurs with nginx's one
|
location = /50x.html {
|
||||||
#
|
root /opt/bitnami/nginx/html;
|
||||||
#location ~ /\.ht {
|
}
|
||||||
# deny all;
|
}
|
||||||
#}
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
worker_processes 1;
|
worker_processes 4;
|
||||||
|
|
||||||
error_log /var/log/nginx/error.log;
|
error_log /opt/bitnami/nginx/logs/error.log;
|
||||||
pid /var/run/nginx.pid;
|
pid /opt/bitnami/nginx/tmp/nginx.pid;
|
||||||
|
|
||||||
events {
|
events {
|
||||||
worker_connections 1024;
|
worker_connections 1024;
|
||||||
@ -11,8 +11,8 @@ http {
|
|||||||
include mime.types;
|
include mime.types;
|
||||||
default_type application/octet-stream;
|
default_type application/octet-stream;
|
||||||
|
|
||||||
access_log /var/log/nginx/proxy_access.log;
|
access_log /opt/bitnami/nginx/logs/proxy_access.log;
|
||||||
error_log /var/log/nginx/proxy_error.log;
|
error_log /opt/bitnami/nginx/logs/proxy_error.log;
|
||||||
|
|
||||||
sendfile on;
|
sendfile on;
|
||||||
keepalive_timeout 180s;
|
keepalive_timeout 180s;
|
||||||
@ -23,6 +23,12 @@ http {
|
|||||||
POST 1;
|
POST 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client_body_temp_path /opt/bitnami/nginx/tmp/client_temp;
|
||||||
|
proxy_temp_path /opt/bitnami/nginx/tmp/proxy_temp_path;
|
||||||
|
fastcgi_temp_path /opt/bitnami/nginx/tmp/fastcgi_temp;
|
||||||
|
uwsgi_temp_path /opt/bitnami/nginx/tmp/uwsgi_temp;
|
||||||
|
scgi_temp_path /opt/bitnami/nginx/tmp/scgi_temp;
|
||||||
|
|
||||||
proxy_cache_path /dev/shm levels=1:2 keys_zone=mcache:16m inactive=600s max_size=512m;
|
proxy_cache_path /dev/shm levels=1:2 keys_zone=mcache:16m inactive=600s max_size=512m;
|
||||||
proxy_cache_methods GET HEAD;
|
proxy_cache_methods GET HEAD;
|
||||||
proxy_cache_min_uses 1;
|
proxy_cache_min_uses 1;
|
||||||
|
Reference in New Issue
Block a user