How to run a WordPress on Kubernetes on port 80

Cluster information:

Kubernetes version: v1.32.3
Cloud being used: bare metal
Installation method: kubeadm
Host OS: Ubuntu 20
CNI and version: Calico v3.25.0
CRI and version: Not sure, but containerd --version shows 1.7.24

It’s been around a month or more that I’m struggling this issue and it’s really driving me crazy:(

What I’m looking for

Deploying a simple WordPress application on K8S cluster on port 80 (not any other NodePort ports) and only on specific domain (like wp.saeed.com).

These are steps I did so far (and as I googled and used AIs also):

  1. Installed K8S cluster using apt install -y kubelet kubectl kubeadm on one worker and one master (that’s for testing only, but I can increase server numbers if needed). Both can see each other and kubectl get nodes shows both Ready.

  2. Run these commands on master:

kubeadm init --control-plane-endpoint="$(hostname)" --upload-certs --pod-network-cidr=192.168.0.0/16
mkdir -p $HOME/.kube
ln -sf /etc/kubernetes/admin.conf $HOME/.kube/config

kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.0/manifests/calico.yaml

ssh -n worker1 "mkdir -pv $HOME/.kube"
rsync /etc/kubernetes/admin.conf worker1:$HOME/.kube/config
token=$(kubeadm token create --print-join-command)
ssh -n worker1 "$token"
sleep 15

kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.12/config/manifests/metallb-native.yaml
kubectl wait --namespace metallb-system \
    --for=condition=ready pod \
    --selector=app=metallb \
    --timeout=90s

sleep 30
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.1/deploy/static/provider/cloud/deploy.yaml
sleep 30

cat <<EOF > /root/metallb.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: default-pool
  namespace: metallb-system
spec:
  addresses:
    - 192.168.100.10/32
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: default-l2
  namespace: metallb-system
spec:
  ipAddressPools:
    - default-pool
  interfaces:
    - $(ip a | grep $(hostname -I | awk -F ' ' '{print $1}') | awk -F ' ' '{print $NF}')
EOF
kubectl apply -f /root/metallb.yaml
rm -vf /root/metallb.yaml

That’s how I run a cluster, deploying ingress-controller, calico and metallb.

I use metallb because I have a dedicated server with some IPs (let’s suppose my public available IPs are 192.168.100.10-192.168.100.20).

I specified 192.168.100.11 to the master as fixed IP in netplan file, and 192.168.100.12 to the worker as Floating IP (I mean this IP is not shown in the ip a output command).

Both worker and master are in a private network 10.10.73.0/24 that can see and ping each other.

Master has two IPs: private and public, while worker has one private only.

  1. After setting everything up, I do these:
  • create namespace
  • create role_based_authorization (rbac) to ensure every namespace can only see its things:
"rules": [
    {
        "apiGroups": [""],
        "resources": ["pods", "services", "deployments"],
        "verbs": ["get", "list", "watch", "create", "update", "patch", "delete"]
    }
]
  • create RoleBinding
  • create deployment on that namespace, and application like wordpress, and containerPort: 80
  • create service like this:
if self.create_service:
    service_manifest = {
        "apiVersion": "v1",
        "kind": "Service",
        "metadata": {
            "name": self.name,
            "namespace": self.namespace.name
        },
        "spec": {
            "type": "ClusterIP",
            "selector": {
                "app": self.name
            },
            "ports": [
                {
                    "protocol": "TCP",
                    "port": self.application.port,
                    "targetPort": self.application.port
                }
            ]
        }
    }
  • create ingress on that namespace, with things like:
ingress_manifest = {
    "apiVersion": "networking.k8s.io/v1",
    "kind": "Ingress",
    "metadata": {
        "name": f"{self.name}-ingress",
        "namespace": self.namespace.name,
        "annotations": {
            "nginx.ingress.kubernetes.io/rewrite-target": "/"
        }
    },
    "spec": {
        'ingressClassName': 'nginx',
        "rules": [
            {
                "host": self.domain,
                "http": {
                    "paths": [
                        {
                            "path": "/",
                            "pathType": "Prefix",
                            "backend": {
                                "service": {
                                    "name": self.name,
                                    "port": {
                                        "number": self.application.port
                                    }
                                }
                            }
                        }
                    ]
                }
            }
        ]
    }
}

I also edit /etc/hosts to point domain to both worker or master IP, but wp.saeed.com shows Connection Refused.

Did I write enough information regarding the issue?

How can I reach what I’m looking for?

1 Like