Run a K3s cluster in docker-compose with PHP + Nginx on 1 Gb, 1 vCPU server.
If anything goes wrong: read documents; check if the versions match (things are changing every day)
At the end of this page includes a list of links used as reference when writing.
Table of Content
- Table of Content
- Environment
- Prerequisites
- Set Up Directory
- Launch the Cluster using Docker-Compose
- Talk to the Cluster
- Create Cluster Configs
- Config and Run the Cluster
- Result
- Stop and Clean up
- Conclusion and Thoughts
- Future Works
- Reference
Environment
- 1 GB Memory
- 1 vCPU
- 25 GB SSD
- Debian 10.2 on Digital Ocean Droplet
Prerequisites
- docker
- docker-compose
- a domain if wish to use https (and certificates)
Try this to set up but it’s more stable to use iptables
at this moment (01/04/2020):
Set Up Debian 10 Server on Digital Ocean
Set Up Directory
Feel free to choose any work directory, but for the purpose of simplicity, a directory owned by a non-root user in the root directory (/
) will be used for this task.
1 | sudo mkdir -v /docker/ |
To make it easier to manage and run scripts, create a bin
directory
- here it is under
/docker/
- alternatively, put it under
~/
, some distribution will automatically append it to$PATH
- (
$PATH
is a list of directories that the shell will use to look for commands/executables)
- (
- editing the
$PATH
variable is optional- it makes calling the script the same as calling normal commands
1 | mkdir -v /docker/bin/ |
It doesn’t hurt to create several sub-directories for:
- Kubernetes resource yaml files
- volumes to mount
1 | mkdir -v /docker/k3s |
Launch the Cluster using Docker-Compose
As easy as one simple docker-compile file from k3s official repo
Modifications:
- rename services
- disable
traefik
by--no-deploy traefik
- mount directory with kubeconfig to host’s
./k3s
(created above) - mount php-code directory to container’s
/var/www
- open 80 and 443 (http/https) port for agents
1 | # to run define K3S_TOKEN, K3S_VERSION is optional, eg: |
Let’s create a script to run it:
1 | touch /docker/bin/k3s-up |
Inside the up script:
1 |
|
Now we just need to run this script
- since the directory is in
$PATH
, we can call it directly - it creates 1 agent by default, can change it by providing command line argument
1 | k3s-up # spawn 1 agents |
Due to extreme memory constrain, let’s begin with 1 agent
Talk to the Cluster
Now the k3s cluster is up and running.
The system might go through a short thrashing period but it will settle down soon (tested on real machine).
It’s time to kubectl
. Let’s use the $KUBECONFIG
variable to simplify things:
1 | export KUBECONFIG=/docker/k3s/kubeconfig.yaml |
Might as well add this line to bashrc (optional):
- so that current user’s shell will automatically set KUBECONFIG variable
1 | echo "export KUBECONFIG=/docker/k3s/kubeconfig.yaml" >> ~/.bashrc |
Test connection
1 | kubectl get nodes |
If not working, consult docker
and other logs
1 | docker ps |
Create Cluster Configs
Attempts to use nginx ingress have been made in vain because of the limited resources.
We shall use our own nginx, plus load balancer service provided by k3s
(good to be simple for simple tasks).
Start with the config maps:
- note: provided nginx configs may not suit every one’s need
1 | mkdir /docker/kube/config-nginx-key # SSL key, if intend to use https |
Let’s go through each config file
- main reference for nginx config
SSL Key
(skip if using http)
Files in /docker/kube/config-nginx-key
:
1 | # SSL certificates |
For security reasons, my own SSL certificates will not be included here.
- Because I use Cloudflare, my cluster uses Cloudflare Origin CA certificates
- Also it does not require complex verification, renewal steps etc.
- If not suitable, might consider a cert manager (linked article uses ingress). That is beyond of the scope of this article
Nginx Snippets
Files in /docker/kube/config-nginx-snippets
:
1 | ssl-some.host.conf |
ssl-some.host.conf
- just telling nginx which certificates to use
1 | ssl_certificate /etc/nginx/ssl-key/cert.pem; |
ssl-params.conf
- cipherli.st
- String SSL Security On Nginx
- Security/Server Side TLS - MozillaWiki
- also if you are using Cloudflare like I do, end-users may see different headers etc.
- since clients are talking to Cloudflare, not the host machine directly in general cases
1 | # SSL |
security.conf
1 | # security headers |
Nginx Site
1 | /docker/kube/config-nginx-sites/php.conf |
Heavily inspired by:
Choose one of the below:
- http
1 | server { |
- https
1 | server { |
Back to our kubernetes cluster, now we need to create:
- PHP code
- PHP service
- PHP deployment
- nginx service LoadBalancer
- nginx deployment
1 | mkdir -v /docker/kube/objects |
Will use one file for related resources
PHP code
For simplicity, the PHP code is directly put into /docker/www
Sample PHP file, put to /docker/www/index.php
:
1 |
|
PHP Resources
1 | editor /docker/kube/objects/php.yaml |
Inside the yaml:
- it exposes port 9000 via ClusterIP (default networking for service) for php-fpm
- php:7-fpm image is used
- the php code directory mounted earlier,
/var/www
, is mounted as ahostPath
volume
1 | apiVersion: v1 |
Nginx Resources
1 | editor /docker/kube/objects/nginx.yaml |
Inside the yaml:
- a LoadBalancer service is created with port 80 and 443
- thanks to k3s’s networking, normally a bare-mental kubernetes cannot use LoadBalancer services
- (“LoadBalancer services … points to external load balancers that are NOT in your cluster”)
- a deployment is created using nginx:1.16 image
- a naive and simple approach to test the config online is included
- the config maps to be created are mounted as directories
- about nginx conf:
- nginx will automatically load conf in
/etc/nginx/conf.d
- for our case, our php.conf will include all other config files
- nginx will automatically load conf in
1 | apiVersion: v1 |
Config and Run the Cluster
Now we have both the configs and the Kubernetes resources files ready.
Just a short script will do all the setup
1 | touch /docker/bin/k3s-setup |
Inside the setup script
1 |
|
Run the script
1 | k3s-setup |
Result
The whole server might suffer from a short period of thrashing after starting everything.
Assume all firewall, certificates and so forth all set up, go to http://host-ip
or https://some.host
(depend on your choice).
The PHP application will show up.
Each access to my host leads to around 40K context switches.
Stop and Clean up
If encounter errors in the previous steps, or need a graceful shutdown, here is a nothing-left-behind clean up script.
1 | touch /docker/bin/k3s-down |
Inside the down script:
- shut down via docker-compose
- remove the used master server volume
1 | # the existence of this variable is required by the docker-compose file |
Conclusion and Thoughts
The purpose of Kubernetes is not, clearly, doing things like this.
But the k3s cluster created is perfect for dev and testing, especially for single-machine. And it’s fun to run a fully-functional Kubernetes on the cutest VPS!
Future Works
- make the cluster persistent
- currently cleaning everything up
- might use
docker-compose stop
, but ideally only the master data is needed - potentially related: How to make a full backup of k3s server’s data? · Issue #927 · rancher/k3s
- use secrets
Reference
Some of documents/tutorials are not updated or no longer working.
Tutorials
- How To Deploy a PHP Application with Kubernetes on Ubuntu 18.04 | DigitalOcean
- How to Set Up an Nginx Ingress with Cert-Manager on DigitalOcean Kubernetes | DigitalOcean
- docker-composeでK3sを試してみた - Qiita
- Single node Kubernetes setup – /techblog
- How To Create a Kubernetes Cluster Using Kubeadm on Ubuntu 18.04 | DigitalOcean
K3s
- Installation Options
- Networking
- Advanced Options and Configuration
- Volumes and Storage
- local-path-provisioner/README.md at master · rancher/local-path-provisioner
Kubernetes
- K3s, minikube or microk8s? : kubernetes
- Resources + Controllers Overview · The Kubectl Book
- Debug Pod Replication Controller - Kubernetes
- Creating a single control-plane cluster with kubeadm - Kubernetes
Kubernetes Volumes
- Volumes - Kubernetes hostPath
- Configure a Pod to Use a ConfigMap - Kubernetes
- Persistent Volumes - Kubernetes
- Kubernetes 1.14: Local Persistent Volumes GA - Kubernetes
- Storage Classes - Kubernetes local
- community/resources.md at master · kubernetes/community
Kubernetes Networking
- Ingress vs Load Balancer
- Ingress - Kubernetes
- Bare-metal considerations - NGINX Ingress Controller
- Exposing FCGI services - NGINX Ingress Controller
- symfony - NGINX - PHP-FPM multiple application K8s/Ingress - Stack Overflow
- ingress-nginx/docs/examples/multi-tls at master · kubernetes/ingress-nginx
Nginx config
- Strong SSL Security on nginx - Raymii.org
- h5bp/server-configs-nginx: Nginx HTTP server boilerplate configs
- Remove deprecated ciphers and protocols by aeris · Pull Request #190 · h5bp/server-configs-nginx
- Use modern SSL config for Nginx by swalkinshaw · Pull Request #1127 · roots/trellis
- Security/Server Side TLS - MozillaWiki
- CryptCheck