Create a k8s development environment by Minikube
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: https://git-scm.com/downloads 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"

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:
https://git-scm.com/downloads
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 "$Home\\Documents\\projects\\test-project\\mounttest:/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:
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"