Skip to content

Commit

Permalink
Init dockerization and kube hosting
Browse files Browse the repository at this point in the history
  • Loading branch information
greedybro committed May 22, 2024
1 parent c6899e8 commit 0aae0ca
Show file tree
Hide file tree
Showing 8 changed files with 469 additions and 0 deletions.
178 changes: 178 additions & 0 deletions .github/workflows/deploy_kube.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
name: Deploy production on Kube

on:
workflow_dispatch: ~
schedule:
- cron: '30 7 * * 1,2,3,4,5' # At 08:30 (UTC, => 08:30 / 09:30 in Europe/Paris depending on the DST), each day of the week.
push:
branches:
- kube

jobs:

build-production:
name: '🚧 Build 🚀'
runs-on: ubuntu-latest
timeout-minutes: 10

environment:
name: production
url: https://www.elao.io #${{ vars.WEBSITE_URL }}

permissions:
contents: read
packages: write

steps:
- name: 'Checkout'
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: 'Configure deployer SSH key'
uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.SSH_DEPLOY_KEY_PRODUCTION }}

# https://github.com/actions/setup-node
- name: 'Setup node'
uses: actions/setup-node@v3
with:
node-version: '20'
cache: 'npm'

- name: 'Setup PHP'
uses: shivammathur/setup-php@v2
with:
coverage: "none"
ini-values: "memory_limit=-1"
php-version: "8.3"

- name: 'Cache resized images'
uses: actions/cache@v3
with:
path: public/resized
key: resized-images-${{ github.workflow }}-${{ secrets.CACHE_VERSION }}

- name: 'Determine composer cache directory'
id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT

- name: 'Cache composer dependencies'
uses: actions/cache@v3
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-

- name: 'Install dependencies'
run: |
echo "::group::composer install"
composer install --no-progress --ansi
echo "::endgroup::"
echo "::group::npm install"
npm install --color=always --no-progress --no-audit --no-fund
echo "::endgroup::"
- name: 'Warmup'
run: |
echo "::group::warmup production env"
npx encore production --color
bin/console cache:clear --ansi
bin/console cache:warmup --ansi
echo "::endgroup::"
env:
APP_ENV: prod

- name: 'Build static site'
run: |
bin/console stenope:build --no-interaction -vv --ansi --ignore-content-not-found
bin/console app:generate-redirections --target=site --no-interaction -vv --ansi > build/redirections-site.conf
bin/console app:generate-redirections --target=blog --no-interaction -vv --ansi > build/redirections-blog.conf
env:
APP_ENV: prod
ROUTER_DEFAULT_URI: https://www.elao.io #${{ vars.WEBSITE_URL }}
INCLUDE_SAMPLES: 0
SHOW_UNPUBLISHED_ARTICLES: 0
MATOMO_ID: ${{ vars.MATOMO_ID }}

- name: 'Login to GitHub Container Registry'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ElaoBot
password: ${{ secrets.GITHUB_TOKEN }}

- name: 'Replace values for production'
run: |
sed -i 's/__REDIRECTIONIO_ELAO_PROJECT_KEY__/${{ secrets.REDIRECTIONIO_ELAO_PROJECT_KEY }}/g' kubernetes/app.conf
sed -i 's/__REDIRECTIONIO_BLOG_PROJECT_KEY__/${{ secrets.REDIRECTIONIO_BLOG_PROJECT_KEY }}/g' kubernetes/app.conf
- name: 'Build and push the Docker image for prod'
uses: docker/build-push-action@v5
with:
context: .
file: kubernetes/Dockerfile
push: true
cache-from: type=gha
cache-to: type=gha,mode=max
tags: |
ghcr.io/elao/website:latest
deploy-helm:
runs-on: ubuntu-22.04
timeout-minutes: 5
needs: [build-production]

steps:
- name: 'Set the Kubernetes context'
uses: azure/k8s-set-context@v4
with:
method: kubeconfig
kubeconfig: $${{ secrets.KUBERNETES_KUBECONFIG }}
context: kubernetes-admin@elao_argon-website-prod

- name: Checkout source code
uses: actions/checkout@v4

- name: 'Render charts website'
uses: azure/k8s-bake@v2.4
id: bake_website
with:
renderEngine: helm
helmChart: kubernetes/charts/website
helm-version: latest
silent: false

- name: 'Deploy to the Kubernetes cluster'
uses: azure/k8s-deploy@v5
with:
action: deploy
force: true
namespace: website-prod
manifests: ${{ steps.bake_website.outputs.manifestsBundle }}
pull-images: false

deploy-image:
runs-on: ubuntu-22.04
timeout-minutes: 5
needs: [deploy-helm]

steps:
- name: 'Set the Kubernetes context'
uses: azure/k8s-set-context@v4
with:
method: kubeconfig
kubeconfig: $${{ secrets.KUBERNETES_KUBECONFIG }}
context: kubernetes-admin@elao_argon-website-prod

- uses: azure/setup-kubectl@v4
name: Setup kubectl
with:
version: v1.28.2

- name: 'Rollout deployment website'
run: |
kubectl rollout restart deployment/website --namespace website-prod
63 changes: 63 additions & 0 deletions kubernetes/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
ARG DEBIAN=bookworm

FROM debian:${DEBIAN}-slim

ARG DEBIAN
ARG NGINX_VERSION=1.22
ARG USER_ID=1000
ARG GROUP_ID=1000

RUN apt-get update \
&& apt-get install -y --no-install-recommends \
apt-transport-https \
ca-certificates \
curl \
gnupg2 \
sudo

# User
RUN addgroup --gid ${GROUP_ID} app \
&& adduser --home /home/app --shell /bin/bash --uid ${USER_ID} --gecos app --ingroup app --disabled-password app \
&& echo "app ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/app \
# App dir
&& mkdir --parents /srv && chown app:app /srv

#########
# Nginx #
#########
RUN \
echo "deb http://nginx.org/packages/debian/ ${DEBIAN} nginx" > /etc/apt/sources.list.d/nginx.list \
&& curl -sSL http://nginx.org/keys/nginx_signing.key \
| apt-key add - \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
nginx=${NGINX_VERSION}.* \
&& chown -R $USER_ID:0 /etc/nginx \
&& chmod -R g+w /etc/nginx

##################
# Redirection.io #
##################
RUN curl -sSL https://packages.redirection.io/gpg.key | apt-key add - \
&& echo "deb https://packages.redirection.io/deb/stable/2 ${DEBIAN} main" > /etc/apt/sources.list.d/packages_redirection_io_deb.list \
&& apt-get update \
&& apt-get install -y \
libnginx-mod-redirectionio

#################
# Configuration #
#################
COPY --chown=app:app kubernetes/app.conf /etc/nginx/app.conf
COPY --chown=app:app build/ /srv/app/website/

#########
# Clean #
#########
RUN \
rm -rf \
/var/lib/apt/lists/* \
/var/cache/debconf/*-old \
/var/lib/dpkg/*-old \
&& truncate -s 0 /var/log/*.log

CMD ["nginx", "-c", "/etc/nginx/app.conf"]
85 changes: 85 additions & 0 deletions kubernetes/app.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
include /etc/nginx/modules-enabled/*.conf;
worker_processes 1;

error_log stderr "warn";
pid /etc/nginx/nginx.pid;

events {
worker_connections 1024;
multi_accept on;
use epoll;
}

daemon off;

http {
include /etc/nginx/mime.types;

proxy_temp_path /tmp/proxy_temp;
client_body_temp_path /tmp/client_temp;
fastcgi_temp_path /tmp/fastcgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
scgi_temp_path /tmp/scgi_temp;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

log_format json escape=json '{'
'"remote_addr": "$remote_addr",'
'"remote_user": "$remote_user",'
'"time_local": "$time_local",'
'"request": "$request",'
'"request_length": $request_length,'
'"status": $status,'
'"body_bytes_sent": $body_bytes_sent,'
'"http_host": "$http_host",'
'"http_referer": "$http_referer",'
'"http_user_agent": "$http_user_agent",'
'"http_x_forwarded_for": "$http_x_forwarded_for",'
'"request_time": $request_time,'
'"upstream_connect_time": "$upstream_connect_time",'
'"upstream_header_time": "$upstream_header_time",'
'"upstream_response_time": "$upstream_response_time"'
'}';

access_log /dev/stdout json;

server {
listen 8080;
server_name www.elao.io;
root /srv/app/website;
absolute_redirect off;
redirectionio_project_key __REDIRECTIONIO_ELAO_PROJECT_KEY__;
gzip on;
gzip_disable msie6;
gzip_vary on;
gzip_proxied expired no-cache no-store private auth;
gzip_comp_level 6;
gzip_min_length 1000;
gzip_types text/css text/javascript text/xml text/plain application/javascript application/x-javascript application/json application/xml application/rss+xml font/truetype application/x-font-ttf font/opentype application/vnd.ms-fontobject image/svg+xml;
# https://scotthelme.co.uk/hardening-your-http-response-headers/
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy strict-origin-when-cross-origin;
add_header Feature-Policy 'geolocation \'self\';fullscreen \'self\';microphone \'none\';camera \'none\';autoplay \'none\';payment \'none\';speaker \'none\'';
location ~* ^.+\.(?:css|cur|js|jpe?g|gif|htc|ico|png|xml|otf|ttf|eot|woff|woff2|svg|webp)$ {
expires 60d;
add_header Cache-Control public;
}
location / {
try_files $uri $uri/index.html =404;
}
location ~ \.html {
internal;
}
error_page 404 /404.html;
}

server {
listen 8080;
server_name blog.elao.io;
redirectionio_project_key __REDIRECTIONIO_BLOG_PROJECT_KEY__;
}
}
3 changes: 3 additions & 0 deletions kubernetes/charts/website/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
apiVersion: v2
name: website
version: 0.0.1
47 changes: 47 additions & 0 deletions kubernetes/charts/website/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "name" -}}
{{- .Chart.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "fullname" -}}
{{- $name := .Chart.Name -}}
{{- if contains $name .Chart.Name -}}
{{- .Chart.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Chart.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Common labels
*/}}
{{- define "labels" -}}
helm.sh/chart: {{ include "chart" . }}
{{ include "selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "selectorLabels" -}}
app.kubernetes.io/name: {{ include "name" . }}
app.kubernetes.io/instance: {{ .Chart.Name }}
{{- end }}

0 comments on commit 0aae0ca

Please sign in to comment.