diff --git a/README.md b/README.md index 981f5ea2c..f7fe89e64 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,10 @@ While intermediate updates can be skipped when updating please make sure to **re 2. Pull the latest image using `docker-compose pull` 3. Start the container again using `docker-compose up -d` +## Kubernetes + +You can find a basic kubernetes setup [here](docs/k8s/). Please see the README in the folder for more detail. + # Documentation Most things should be straight forward but there are some more complicated things. diff --git a/docs/k8s/10-configmap.yaml b/docs/k8s/10-configmap.yaml new file mode 100644 index 000000000..8a939d081 --- /dev/null +++ b/docs/k8s/10-configmap.yaml @@ -0,0 +1,33 @@ +kind: ConfigMap +apiVersion: v1 +metadata: + labels: + app: recipes + name: recipes-nginx-config +data: + nginx-config: |- + events { + worker_connections 1024; + } + http { + server { + listen 80; + server_name _; + + client_max_body_size 16M; + + # serve static files + location /static/ { + alias /static/; + } + # serve media files + location /media/ { + alias /media/; + } + # pass requests for dynamic content to gunicorn + location / { + proxy_set_header Host $host; + proxy_pass http://localhost:8080; + } + } + } diff --git a/docs/k8s/30-pv.yaml b/docs/k8s/30-pv.yaml new file mode 100644 index 000000000..810a5f34e --- /dev/null +++ b/docs/k8s/30-pv.yaml @@ -0,0 +1,50 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: recipes-db + labels: + app: recipes + type: local + tier: db +spec: + storageClassName: manual + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + hostPath: + path: "/data/recipes/db" +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: recipes-media + labels: + app: recipes + type: local + tier: media +spec: + storageClassName: manual + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + hostPath: + path: "/data/recipes/media" +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: recipes-static + labels: + app: recipes + type: local + tier: static +spec: + storageClassName: manual + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + hostPath: + path: "/data/recipes/static" diff --git a/docs/k8s/30-pvc.yaml b/docs/k8s/30-pvc.yaml new file mode 100644 index 000000000..16b8b48af --- /dev/null +++ b/docs/k8s/30-pvc.yaml @@ -0,0 +1,52 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: recipes-db + labels: + app: recipes +spec: + selector: + matchLabels: + tier: db + storageClassName: manual + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: recipes-media + labels: + app: recipes +spec: + selector: + matchLabels: + tier: media + app: recipes + storageClassName: manual + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: recipes-static + labels: + app: recipes +spec: + selector: + matchLabels: + tier: static + app: recipes + storageClassName: manual + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi diff --git a/docs/k8s/50-deployment.yaml b/docs/k8s/50-deployment.yaml new file mode 100644 index 000000000..a64e5e445 --- /dev/null +++ b/docs/k8s/50-deployment.yaml @@ -0,0 +1,102 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: recipes + labels: + app: recipes + environment: production + tier: frontend +spec: + replicas: 1 + strategy: + type: RollingUpdate + selector: + matchLabels: + app: recipes + environment: production + template: + metadata: + labels: + app: recipes + environment: production + spec: + containers: + - name: recipes-nginx + image: nginx:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 80 + protocol: TCP + name: http + volumeMounts: + - mountPath: '/media' + name: media + - mountPath: '/static' + name: static + - name: nginx-config + mountPath: /etc/nginx/nginx.conf + subPath: nginx-config + readOnly: true + - name: recipes + image: 'vabene1111/recipes:latest' + imagePullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: / + port: 8080 + readinessProbe: + httpGet: + path: / + port: 8080 + volumeMounts: + - mountPath: '/opt/recipes/mediafiles' + name: media + - mountPath: '/opt/recipes/staticfiles' + name: static + env: + - name: DEBUG + value: "0" + - name: ALLOWED_HOSTS + value: '*' + - name: SECRET_KEY + value: # CHANGEME + - name: DB_ENGINE + value: django.db.backends.postgresql_psycopg2 + - name: POSTGRES_HOST + value: localhost + - name: POSTGRES_PORT + value: "5432" + - name: POSTGRES_USER + value: recipes + - name: POSTGRES_DB + value: recipes + - name: POSTGRES_PASSWORD + value: # CHANGEME + - name: recipes-db + image: 'postgres:latest' + imagePullPolicy: IfNotPresent + ports: + - containerPort: 5432 + volumeMounts: + - mountPath: '/var/lib/postgresql/data' + name: database + env: + - name: POSTGRES_USER + value: recipes + - name: POSTGRES_DB + value: recipes + - name: POSTGRES_PASSWORD + value: # CHANGEME + volumes: + - name: database + persistentVolumeClaim: + claimName: recipes-db + - name: media + persistentVolumeClaim: + claimName: recipes-media + - name: static + persistentVolumeClaim: + claimName: recipes-static + - name: nginx-config + configMap: + name: recipes-nginx-config diff --git a/docs/k8s/60-service.yaml b/docs/k8s/60-service.yaml new file mode 100644 index 000000000..0becd59f3 --- /dev/null +++ b/docs/k8s/60-service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: recipes + labels: + app: recipes +spec: + selector: + app: recipes + environment: production + ports: + - port: 80 + targetPort: http + name: http + protocol: TCP diff --git a/docs/k8s/README.md b/docs/k8s/README.md new file mode 100644 index 000000000..09c5187ad --- /dev/null +++ b/docs/k8s/README.md @@ -0,0 +1,25 @@ +# Kubernetes + +This is a basic kubernetes setup. Please note that this does not necessarily follow Kubernetes best practices and should only used as a basis to build your own setup from! + +## Important notes + +State (database, static files and media files) is handled via `PersistentVolumes`. + +Note that you will most likely have to change the `PersistentVolumes` in `30-pv.yaml`. The current setup is only usable for a single-node cluster because it uses local storage on the kubernetes worker nodes under `/data/recipes/`. It should just serve as an example. + +Currently, the deployment in `50-deployment.yaml` just pulls the `latest` tag of all containers. In a production setup, you should set this to a fixed version! + +See env variables tagged with `CHANGEME` in `50-deployment.yaml` and make sure to change those! A better setup would use kubernetes secrets but this is not implemented yet. + +## Updates + +These manifests are not tested against new versions. + +## Apply the manifets + +To apply the manifest with `kubectl`, use the following command: + +``` +kubectl apply -f ./docs/k8s/ +```