diff --git a/.github/workflows/containers-publish.yml b/.github/workflows/containers-publish.yml new file mode 100644 index 00000000..9d5ce469 --- /dev/null +++ b/.github/workflows/containers-publish.yml @@ -0,0 +1,68 @@ +name: 'Containers: Publish' + +on: + push: + tags: [ 'v*' ] + + +jobs: + release-containers: + name: Build and Push + runs-on: ubuntu-latest + steps: + + - uses: actions/checkout@v3 + + - name: Login to ghcr.io Docker registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Compute Docker container image addresses + run: | + DOCKER_REPOSITORY="ghcr.io/${GITHUB_REPOSITORY,,}" + DOCKER_TAG="${GITHUB_REF:11}" + + echo "DOCKER_REPOSITORY=${DOCKER_REPOSITORY}" >> $GITHUB_ENV + echo "DOCKER_TAG=${DOCKER_TAG}" >> $GITHUB_ENV + + echo "Using: ${DOCKER_REPOSITORY}/*:${DOCKER_TAG}" + + # - name: 'Pull previous Docker container image: :latest' + # run: docker pull "${DOCKER_REPOSITORY}:latest" || true + + - name: 'Pull previous Docker container image: frontend-static:latest' + run: docker pull "${DOCKER_REPOSITORY}/frontend-static:latest" || true + + - name: 'Build Docker container image: frontend-static:latest' + run: | + docker build \ + --cache-from "${DOCKER_REPOSITORY}/frontend-static:latest" \ + --file frontend/Dockerfile.demo \ + --build-arg SERVER_NAME=localhost \ + --tag "${DOCKER_REPOSITORY}/frontend-static:latest" \ + --tag "${DOCKER_REPOSITORY}/frontend-static:${DOCKER_TAG}" \ + frontend + - name: 'Push Docker container image frontend-static:latest' + run: docker push "${DOCKER_REPOSITORY}/frontend-static:latest" + + - name: 'Push Docker container image frontend-static:v*' + run: docker push "${DOCKER_REPOSITORY}/frontend-static:${DOCKER_TAG}" +# +# +# - name: 'Build Docker container image: backend:latest' +# run: | +# cd backend && \ +# make && \ +# docker image tag "${DOCKER_REPOSITORY}/backend/local:latest" "${DOCKER_REPOSITORY}/backend:latest" +# +# - name: Push Docker container image backend:latest +# run: docker push "${DOCKER_REPOSITORY}/backend:latest" +# +# - name: Push Docker container image backend:v* +# run: docker push "${DOCKER_REPOSITORY}/backend:${DOCKER_TAG}" + + # - name: Push Docker container image :v*" + # run: docker push "${DOCKER_REPOSITORY}:${DOCKER_TAG}" diff --git a/server/Dockerfile.prod b/Dockerfile.prod similarity index 85% rename from server/Dockerfile.prod rename to Dockerfile.prod index fe448bab..5b979a4e 100644 --- a/server/Dockerfile.prod +++ b/Dockerfile.prod @@ -1,9 +1,10 @@ +# This image runs the production server, with nginx ########### # BUILDER # ########### # pull official base image -FROM python:3.11.4-slim-buster as builder +FROM python:3.11.4-slim-buster as python_builder # set work directory WORKDIR /usr/src/app @@ -48,8 +49,8 @@ WORKDIR $APP_HOME # install dependencies RUN apt-get update && apt-get install -y --no-install-recommends netcat -COPY --from=builder /usr/src/app/wheels /wheels -COPY --from=builder /usr/src/app/requirements.txt . +COPY --from=python_builder /usr/src/app/wheels /wheels +COPY --from=python_builder /usr/src/app/requirements.txt . RUN pip install --upgrade pip RUN pip install --no-cache /wheels/* @@ -69,3 +70,6 @@ USER app # run entrypoint.prod.sh ENTRYPOINT ["/home/app/web/entrypoint.prod.sh"] + + +# TODO: gunicorn stuff \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.dev.yml similarity index 87% rename from docker-compose.yml rename to docker-compose.dev.yml index 042f0073..67ab99f3 100644 --- a/docker-compose.yml +++ b/docker-compose.dev.yml @@ -12,7 +12,7 @@ services: build: ./server command: python manage.py runserver 0.0.0.0:8000 volumes: - - ./server:/usr/src/server + - ./server:/usr/src/app ports: - "8000:8000" env_file: @@ -23,9 +23,10 @@ services: image: balancer-frontend build: context: frontend - dockerfile: Dockerfile + dockerfile: Dockerfile.dev args: - IMAGE_NAME=balancer-frontend + - FRONTEND_VERSION=0.0.1 ports: - "3000:3000" environment: diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 2a7e43e8..a58e7700 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -5,7 +5,7 @@ services: volumes: - postgres_data:/var/lib/postgresql/data/ env_file: - - ./.env.prod.db + - ./config/env/env.prod.db backend: build: context: ./server @@ -14,22 +14,9 @@ services: ports: - 8000:8000 env_file: - - ./config/env/.env.prod + - ./config/env/env.prod depends_on: - db - frontend: - image: balancer-frontend - build: - context: frontend - dockerfile: Dockerfile - args: - - IMAGE_NAME=balancer-frontend - ports: - - "3000:3000" - environment: - - CHOKIDAR_USEPOLLING=true - depends_on: - - backend volumes: postgres_data: \ No newline at end of file diff --git a/frontend/.gitignore b/frontend/.gitignore index d67a573c..a547bf36 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -22,5 +22,3 @@ dist-ssr *.njsproj *.sln *.sw? - -.DS_Store diff --git a/frontend/Dockerfile.demo b/frontend/Dockerfile.demo new file mode 100644 index 00000000..ecf94591 --- /dev/null +++ b/frontend/Dockerfile.demo @@ -0,0 +1,38 @@ +# This dockerfile builds an image for a static frontend only server suitable for online hosting. +# Use the official Node.js image as the base image +FROM node:18 as builder + +# Set the working directory inside the container +WORKDIR /usr/src/app + +# Copy package.json and package-lock.json +COPY package*.json ./ + +# Set version number +ARG FRONTEND_VERSION +RUN npm version $FRONTEND_VERSION + +# Install dependencies +RUN npm ci --legacy-peer-deps + +# Copy project files +COPY . . + +RUN npm run build + +FROM alpine:latest as nginx-config +RUN apk --no-cache add gettext +WORKDIR /app +COPY nginx.conf.demo ./nginx.conf.demo +# This will get overwritten by helm chart + +ARG SERVER_NAME +ENV SERVER_NAME $SERVER_NAME +RUN cat nginx.conf.demo | envsubst > nginx.conf + +FROM nginx:alpine + +COPY --from=nginx-config /app/nginx.conf /etc/nginx/nginx.conf +COPY --from=Builder /usr/src/app/dist /usr/share/nginx/html + +# The default entrypoint works for us. \ No newline at end of file diff --git a/frontend/Dockerfile b/frontend/Dockerfile.dev similarity index 68% rename from frontend/Dockerfile rename to frontend/Dockerfile.dev index 3b0b404f..b652b980 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile.dev @@ -1,4 +1,5 @@ -# Use the official Node.js 14 image as the base image +# This dockerfile builds an image for a Vite development server +# Use the official Node.js image as the base image FROM node:18 # Set the working directory inside the container @@ -14,12 +15,12 @@ RUN npm ci --legacy-peer-deps COPY . . # Build the project -RUN npm run build +# RUN npm run build # Expose a port if required -EXPOSE 3000 +# EXPOSE 3000 -# Start the application +# Start the dev server CMD [ "npm", "run", "dev" ] # Set the image name diff --git a/frontend/docker-compose.demo.yaml b/frontend/docker-compose.demo.yaml new file mode 100644 index 00000000..652b992f --- /dev/null +++ b/frontend/docker-compose.demo.yaml @@ -0,0 +1,16 @@ +version: "3.8" +services: + frontend-static: + build: + context: . + dockerfile: Dockerfile.demo + args: + - IMAGE_NAME=frontend-static + - FRONTEND_VERSION=0.0.2 + - SERVER_NAME=localhost + image: ghcr.io/codeforphilly/balancer-main/frontend-static:0.0.2 + ports: + - "80:80" + environment: + - CHOKIDAR_USEPOLLING=true + - VITE_API_BASE_URL=https://devnull-as-a-service.com/dev/null diff --git a/frontend/docker-compose.yml b/frontend/docker-compose.dev.yaml similarity index 51% rename from frontend/docker-compose.yml rename to frontend/docker-compose.dev.yaml index 4114849e..3c9916f9 100644 --- a/frontend/docker-compose.yml +++ b/frontend/docker-compose.dev.yaml @@ -3,13 +3,14 @@ services: react-app: build: context: . - dockerfile: Dockerfile + dockerfile: Dockerfile.dev args: - - IMAGE_NAME=balancer-frontend + - IMAGE_NAME=balancer-frontend-dev ports: - "3000:3000" + # The port number is hard-coded, located in ./vite.config.ts environment: - CHOKIDAR_USEPOLLING=true volumes: - "./:/usr/src/app:delegated" - - "/usr/src/app/node_modules/" + - "./node_modules:/usr/src/app/node_modules/" diff --git a/frontend/nginx.conf.demo b/frontend/nginx.conf.demo new file mode 100644 index 00000000..c093b5e4 --- /dev/null +++ b/frontend/nginx.conf.demo @@ -0,0 +1,29 @@ +# nginx config file for static frontend demo site. +# This will be the nginx.conf in the docker image before it gets overwritten by kubernetes helm chart. +user nginx; + worker_processes 1; + events { + worker_connections 1024; + } + http { + include /etc/nginx/mime.types; + server { + listen 80; + listen [::]:80; + server_name $SERVER_NAME; + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + } + + #error_page 404 /404.html; + + # redirect server error pages to the static page /50x.html + # + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } + } + } \ No newline at end of file diff --git a/helm-chart/Chart.yaml b/helm-chart/Chart.yaml new file mode 100644 index 00000000..b990b819 --- /dev/null +++ b/helm-chart/Chart.yaml @@ -0,0 +1,9 @@ +name: nginx-helm-chart +description: A generated Helm Chart for nginx-helm-chart from Skippbox Kompose +version: 0.0.2 +apiVersion: v2 +keywords: + - nginx-helm-chart +sources: + - https://github.com/CodeForPhilly/balancer-main +home: https://opencollective.com/code-for-philly/projects/balancer diff --git a/helm-chart/README.md b/helm-chart/README.md new file mode 100644 index 00000000..2945440b --- /dev/null +++ b/helm-chart/README.md @@ -0,0 +1,2 @@ +Chart initially created by Kompose from nginx-docker-compose.yml + diff --git a/helm-chart/templates/frontend-static-deployment.yaml b/helm-chart/templates/frontend-static-deployment.yaml new file mode 100644 index 00000000..55f98f45 --- /dev/null +++ b/helm-chart/templates/frontend-static-deployment.yaml @@ -0,0 +1,54 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + kompose.cmd: kompose convert -c -f nginx-docker-compose.yml -o nginx-helm-chart + kompose.version: 1.31.2 (a92241f79) + creationTimestamp: null + labels: + io.kompose.service: frontend-static + name: frontend-static +spec: + replicas: 1 + selector: + matchLabels: + io.kompose.service: frontend-static + strategy: + type: Recreate + template: + metadata: + annotations: + kompose.cmd: kompose convert -c -f nginx-docker-compose.yml -o nginx-helm-chart + kompose.version: 1.31.2 (a92241f79) + creationTimestamp: null + labels: + io.kompose.network/frontend-default: "true" + io.kompose.service: frontend-static + spec: + containers: + - env: + - name: CHOKIDAR_USEPOLLING + value: "true" + - name: VITE_API_BASE_URL + value: {{ .Values.VITE_API_BASE_URL }} + + image: ghcr.io/codeforphilly/balancer-main/frontend-static:latest + name: frontend-static + ports: + - containerPort: 80 + protocol: TCP + volumeMounts: + - mountPath: /etc/nginx/nginx.conf + name: nginx-conf + subPath: nginx.conf + readOnly: true + resources: {} + volumes: + - name: nginx-conf + configMap: + name: nginx-conf + items: + - key: nginx.conf + path: nginx.conf + restartPolicy: Always +status: {} diff --git a/helm-chart/templates/frontend-static-service.yaml b/helm-chart/templates/frontend-static-service.yaml new file mode 100644 index 00000000..26c3db19 --- /dev/null +++ b/helm-chart/templates/frontend-static-service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + annotations: + kompose.cmd: kompose convert -c -f nginx-docker-compose.yml -o nginx-helm-chart + kompose.version: 1.31.2 (a92241f79) + creationTimestamp: null + labels: + io.kompose.service: frontend-static + name: frontend-static +spec: + ports: + - name: "http" + port: 80 + protocol: TCP + selector: + io.kompose.service: frontend-static +status: + loadBalancer: {} diff --git a/helm-chart/templates/nginx-configmap.yaml b/helm-chart/templates/nginx-configmap.yaml new file mode 100644 index 00000000..8f1d45bf --- /dev/null +++ b/helm-chart/templates/nginx-configmap.yaml @@ -0,0 +1,45 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: nginx-conf +# https://stackoverflow.com/questions/64178370/custom-nginx-conf-from-configmap-in-kubernetes +data: + nginx.conf: | + user nginx; + worker_processes 1; + events { + worker_connections 1024; + } + http { + include /etc/nginx/mime.types; + error_log /var/log/nginx/error_log; + access_log /var/log/nginx/access_log; + server { + listen 80; + listen [::]:80; + server_name {{ .Values.nginx.serverName }}; + + location /access_log { + alias /var/log/nginx/access_log; + } + location /error_log { + alias /var/log/nginx/error_log; + } + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + } + + #error_page 404 /404.html; + + # redirect server error pages to the static page /50x.html + # + #error_page 500 502 503 504 /50x.html; + #location = /50x.html { + # root /usr/share/nginx/html; + + #} + } + } + diff --git a/helm-chart/values.yaml b/helm-chart/values.yaml new file mode 100644 index 00000000..91b342dd --- /dev/null +++ b/helm-chart/values.yaml @@ -0,0 +1,17 @@ +nginx: + serverName: "localhost" + +VITE_API_BASE_URL: https://devnull-as-a-service.com/dev/null + +ingress: + enabled: false + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: + - path: / + pathType: ImplementationSpecific + tls: [] \ No newline at end of file diff --git a/server/Dockerfile b/server/Dockerfile.dev similarity index 81% rename from server/Dockerfile rename to server/Dockerfile.dev index 74c7b6a7..e79d155b 100644 --- a/server/Dockerfile +++ b/server/Dockerfile.dev @@ -1,3 +1,5 @@ +# This image runs the Django lightweight development web server without the frontend. +# Intended to be run along with the frontend dev server. # pull official base image FROM python:3.11.4-slim-buster