Prerequisites
My environment is Windows10.
Download tools
Please install minikube from here:
https://minikube.sigs.k8s.io/docs/star
Let’s use virtualbox driver for minikube.
Please install virtualbox from here:
http://virtualbox.org/wiki/Downloads
We will use Git too. Please install Git from here:
Let’s install skaffold too:
https://skaffold.dev/docs/install/
Then please install kubernetes too:
https://kubernetes.io/docs/tasks/tools/install-kubectl-windows/
(If you use choco or scoop, it is easy to install)
After installing them, let’s confirm if you can access minikube from Powershell.
Open Powershell then run the following command:
minikube version
Then you get minikube version
minikube version: v1.35.0
commit: dd5d320e41b5451cdf3c01891bc4e13d189586ed-dirty
In the same way, please check git version too:
git -v
git version 2.47.1.windows.2
Now let’s make a test project for this test.
cd Documents
mkdir projects
cd projects
mkdir test-project
cd test-project
Minikube start (minikube cluster)
terminology
What are Containers?
Containers are lightweight, isolated runtime environments that package an application and its dependencies. They ensure consistency across different computing environments.
What are Pods?
A Pod is the smallest deployable unit in Kubernetes, acting as a wrapper for one or more containers.
What is a Cluster?
A Cluster is the highest-level component in Kubernetes, consisting of multiple worker nodes that run Pods.
Start a minikube cluster
Please run this command:
minikube start --driver=virtualbox
Then minikube will start. Please note that, if it is docker driver, you can use mount option like
minikube start --mount --mount-string="$HOME:/src" --driver=docker
but unfortunately this is impossible with virtualbox driver. (but virtualbox is free unlike docker desktop…)
Now let’s install kubernetes. But we will just install kubernetes via minikube:
minikube kubectl -- version
After kubernetes is installed, kubernetes version is displayed like:
minikube kubectl -- version
Client Version: v1.32.0
Kustomize Version: v5.5.0
Server Version: v1.32.0
Create pods
Let’s create PHP, Nginx, MariaDB environment.
At first, enable ingress:
minikube addons enable ingress
Then please save the following as php-mariadb.yaml
. This file contains definition of containers in the pods. Please note that you must use “LF” for this file’s linebreaks not “CRLF”:
# MariaDB Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
# Deployment name
name: mariadb
# Labels for identifying the deployment
labels:
app: mariadb
spec:
# Number of MariaDB instances
replicas: 1
selector:
# Matching labels for pods
matchLabels:
app: mariadb
template:
metadata:
labels:
app: mariadb
spec:
containers:
- name: mariadb
# Docker image for MariaDB
image: mariadb:11.3
# Port on which MariaDB runs
ports:
- containerPort: 3306
# Environment variables for MariaDB
env:
- name: MYSQL_ROOT_PASSWORD
value: "rootpassword"
- name: MYSQL_DATABASE
value: "mydatabase"
- name: MYSQL_USER
value: "myuser"
- name: MYSQL_PASSWORD
value: "mypassword"
# Volume mounting for MariaDB data storage
volumeMounts:
- name: mariadb-storage
mountPath: /var/lib/mysql
# Definition of volumes
volumes:
- name: mariadb-storage
emptyDir: {}
---
# MariaDB Service
apiVersion: v1
kind: Service
metadata:
# Service name for MariaDB
name: mariadb
spec:
ports:
- port: 3306
selector:
# Selector for connecting to MariaDB pods
app: mariadb
---
# PHP Application Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
# Deployment name
name: php-app
# Labels for identifying the PHP deployment
labels:
app: php-app
spec:
# Number of PHP application instances
replicas: 1
selector:
matchLabels:
app: php-app
template:
metadata:
labels:
app: php-app
spec:
containers:
- name: php-app
# Docker image for PHP application
image: php:8.3-apache
# Port on which PHP Apache runs
ports:
- containerPort: 80
# Volume mounting for PHP application code from host machine
volumeMounts:
- name: php-app-code
mountPath: /var/www/html
- name: apache-config
mountPath: /etc/apache2/sites-enabled/000-default.conf
subPath: default
# Definition of volumes
volumes:
- name: php-app-code
hostPath:
path: "/mnt/project"
type: Directory
- name: apache-config
configMap:
name: apache-config
---
# ConfigMap for Apache Configuration
apiVersion: v1
kind: ConfigMap
metadata:
name: apache-config
data:
default: |
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
DirectoryIndex index.html index.php
ErrorLog /var/log/apache2/error.log
CustomLog /var/log/apache2/access.log combined
---
# PHP Application Service
apiVersion: v1
kind: Service
metadata:
# Service name for PHP application
name: php-app-service
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
selector:
# Selector for connecting to PHP pods
app: php-app
---
# Ingress resource for PHP Application
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: php-app-ingress
spec:
ingressClassName: nginx
rules:
- host: localhost
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: php-app-service
port:
number: 80
Then please save the following as skaffold.yaml:
apiVersion: skaffold/v4beta12
kind: Config
metadata:
name: php-mariadb-app
deploy:
kubectl: {}
manifests:
rawYaml:
- php-mariadb.yaml
Now our environment is ready to go!
Before starting our environment, let’s create a mount directory:
mkdir mounttest
minikube mount "$HomeDocumentsprojectstest-projectmounttest:/mnt/project"
This mount command will keep running. For subsequent commands, please open a new terminal and run the commands on it.
Please run this command (please make sure you in the test-project directory):
cd {the test-project directory}
skaffold delete
skaffold run --force
This command will keep running. For subsequent commands, please open a new terminal and run the commands on it.
Please wait a while… Your kubernetes environment is being created in the minikube cluster. This will take time.
See here for more skaffold examples: https://github.com/GoogleContainerTools/skaffold/tree/main/examples
For available paramters: https://skaffold.dev/docs/references/yaml/
Now your php and mariadb should be running. Let’s check it by kubectl get pods
:
kubectl get pods
NAME READY STATUS RESTARTS AGE
mariadb-998f96ddb-84kqs 1/1 Running 0 64s
php-app-bf6f77579-454jl 1/1 Running 0 64s
If all of them are “Ready 1/1”, it means your environment is running without problem.
By the way, these are called pods:
mariadb-998f96ddb-84kqs (pod)
php-app-bf6f77579-454jl (pod)
Our containers defined by the yaml file are in the pods. One pod can have multiple containers inside.
Sometimes we define logger container and put them in the pod together with a php container.
Such containers are called “sidecar container.”
If any of the pods is not ready, please check the pod:
kubectl describe pod php-app-bf6f77579-454jl
Or check the standard output:
kubectl logs php-app-bf6f77579-454jl
To see cluster-wide information:
kubectl get events --sort-by='.metadata.creationTimestamp'
When the creation is done, to access minikube environment from host, let’s run this command:
minikube tunnel
This command will keep running. For subsequent commands, please open a new terminal and run the commands on it.
Mount /var/www/html to the host PC and access the file through ingress
Now let’s see if you can access the ingress. Run this command and get ingress information:
kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
php-app-ingress localhost 192.168.59.100 80 103s
And, following this information, if you access 192.168.59.100 from your browser, you will see 404.
If you can see the 404, you are ready to go further.
Please check the ingress ip by:
kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
php-app-ingress nginx localhost 192.168.59.100 80 93s
My IP is 192.168.59.100, so please update the php-mariadb.yaml’s ingress configuration:
# Ingress resource for PHP Application
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: php-app-ingress
spec:
ingressClassName: nginx
rules:
- host: 192.168.59.100.nip.io #!!! Change here !!!!
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: php-app-service
port:
number: 80
We have mounted our “mounttest” to “/mnt/project” (of minikube) and this “/mnt/project” is mounted again to “/var/www/html” of php-appache pod. So let’s create index.php like this:
<?php
echo "Hello World!";
Please save it in the mounttest
of your project
folder.
Now open http://192.168.59.100.nip.io/ from your browser. You should see Hello World!
If you change the php code, you can see that the change is reflected in real time (if not, please disable opcache from your php.ini). Your PHP code is working in a k8s cluster!
Now you can edit your php in your mounttest
folder and the edit is reflected to the php pod in the kubernetes cluster in real time. If you need, you can even set php debug for your development. But, if you with minikube & kubernetes in your local, please don’t forget to disable opcache in your php.ini:
opcache.enable=0
opcache.validate_timestamps=1
opcache.revalidate_freq=0
Use MariaDB from host pc
Let’s change MariaDB’s service:
# MariaDB Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
# Deployment name
name: mariadb
# Labels for identifying the deployment
labels:
app: mariadb
spec:
# Number of MariaDB instances
replicas: 1
selector:
# Matching labels for pods
matchLabels:
app: mariadb
template:
metadata:
labels:
app: mariadb
spec:
containers:
- name: mariadb
# Docker image for MariaDB
image: mariadb:11.3
# Port on which MariaDB runs
ports:
- containerPort: 3306
# Environment variables for MariaDB
env:
- name: MYSQL_ROOT_PASSWORD
value: "rootpassword"
- name: MYSQL_DATABASE
value: "mydatabase"
- name: MYSQL_USER
value: "myuser"
- name: MYSQL_PASSWORD
value: "mypassword"
# Volume mounting for MariaDB data storage
volumeMounts:
- name: mariadb-storage
mountPath: /var/lib/mysql
# Definition of volumes
volumes:
- name: mariadb-storage
emptyDir: {}
---
kind: Service
apiVersion: v1
metadata:
name: mariadb
spec:
type: NodePort
selector:
app: mariadb
ports:
- port: 3306
targetPort: 3306
protocol: TCP
nodePort: 30036 # for example (must be within the allowed range, e.g., 30000-32767)
---
# PHP Application Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
# Deployment name
name: php-app
# Labels for identifying the PHP deployment
labels:
app: php-app
spec:
# Number of PHP application instances
replicas: 1
selector:
matchLabels:
app: php-app
template:
metadata:
labels:
app: php-app
spec:
containers:
- name: php-app
# Docker image for PHP application
image: php:8.3-apache
# Port on which PHP Apache runs
ports:
- containerPort: 80
# Volume mounting for PHP application code from host machine
volumeMounts:
- name: php-app-code
mountPath: /var/www/html
- name: apache-config
mountPath: /etc/apache2/sites-enabled/000-default.conf
subPath: default
# Definition of volumes
volumes:
- name: php-app-code
hostPath:
path: "/mnt/project"
type: Directory
- name: apache-config
configMap:
name: apache-config
---
# ConfigMap for Apache Configuration
apiVersion: v1
kind: ConfigMap
metadata:
name: apache-config
data:
default: |
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
DirectoryIndex index.html index.php
ErrorLog /var/log/apache2/error.log
CustomLog /var/log/apache2/access.log combined
---
# PHP Application Service
apiVersion: v1
kind: Service
metadata:
# Service name for PHP application
name: php-app-service
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
selector:
# Selector for connecting to PHP pods
app: php-app
---
# Ingress resource for PHP Application
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: php-app-ingress
spec:
ingressClassName: nginx
rules:
- host: 192.168.59.100.nip.io #!!! Change here !!!!
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: php-app-service
port:
number: 80
You can see that the MariaDB service is using NodePort
now.
Stop the skaffold run
from the terminal where you executed the command (by ctrl+c), then start again by:
cd {the test-project directory}
skaffold delete
skaffold run --force
Check minikube IP by:
minikube ip
It will give you the IP address of minikube. You can use this IP and the NodePort to access the MariaDB.
For me, the IP address was 192.168.59.100
The NodePort is defined as 30036 in the yaml file.
So by using both 192.168.59.100:30036, you can access the MariaDB.
Please note that the environment of MariaDB is configured this way:
- name: MYSQL_ROOT_PASSWORD
value: "rootpassword"
- name: MYSQL_DATABASE
value: "mydatabase"
- name: MYSQL_USER
value: "myuser"
- name: MYSQL_PASSWORD
value: "mypassword"