kubectl cannot acces pod application

1/15/2020

A have this pod specification :

apiVersion: v1
kind: Pod
metadata:
  name: wp
spec:
  containers:
  - image: wordpress:4.9-apache
    name: wordpress
    env:
      - name: WORDPRESS_DB_PASSWORD
        value: mysqlpwd
      - name: WORDPRESS_DB_HOST
        value: 127.0.0.1
  - image: mysql:5.7
    name: mysql
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: mysqlpwd
    volumeMounts:
    - name: data
      mountPath: /var/lib/mysql
  volumes:
    - name: data
      emptyDir: {}

I deployed it using :

kubectl create -f wordpress-pod.yaml

Now it is correctly deployed :

kubectl get pods wp 2/2 Running 3 35h

Then when i do :

kubectl describe po/wp

Name:         wp
Namespace:    default
Priority:     0
Node:         node3/192.168.50.12
Start Time:   Mon, 13 Jan 2020 23:27:16 +0100
Labels:       <none>
Annotations:  <none>
Status:       Running
IP:           10.233.92.7
IPs:
  IP:  10.233.92.7
Containers:

My issue is that i cannot access to the app :

wget http://192.168.50.12:8080/wp-admin/install.php
Connecting to 192.168.50.12:8080... failed: Connection refused.

Neither wget http://10.233.92.7:8080/wp-admin/install.php works

Is there any issue in the pod description or deployment process ?

Thanks

-- user1361815
kubernetes
mysql
wordpress

2 Answers

1/16/2020

The problem with your configuration is lack of services that will allow external access to your WordPress.

There a lot of materials explaining what are the options and how they are strictly connected with infrastructure that Kubernetes works on.

Let me elaborate on 3 of them:

  • minikube
  • kubeadm
  • cloud provisioned (GKE, EKS, AKS)

The base of the WordPress configuration will be the same in each case.

Table of contents:

  • Running MySQL
    • Secret
    • PersistentVolumeClaim
    • Deployment
    • Service
  • Running WordPress
    • PersistentVolumeClaim
    • Deployment
  • Allowing external access
    • minikube
    • kubeadm
    • cloud provisioned (GKE)

There is a good tutorial on Kubernetes site: HERE!

Running MySQL

Secret

As the official Kubernetes documentation:

Kubernetes secret objects let you store and manage sensitive information, such as passwords, OAuth tokens, and ssh keys. Putting this information in a secret is safer and more flexible than putting it verbatim in a Pod definition or in a container image.

-- Kubernetes secrets

Example below is a YAML definition of a secret used for MySQL password:

apiVersion: v1
kind: Secret
metadata:
  name: mysql-password
type: Opaque
data:
  password: c3VwZXJoYXJkcGFzc3dvcmQK

Take a specific look at:

  password: c3VwZXJoYXJkcGFzc3dvcmQK

This password is base64 encoded.

To create this password invoke command from your terminal: $ echo "YOUR_PASSWORD" | base64

Paste the output to the YAML definition and apply it with: $ kubectl apply -f FILE_NAME.

You can check if it was created correctly with: $ kubectl get secret mysql-password -o yaml

PersistentVolumeClaim

MySQL require a dedicated space for storing the data. There is an official documentation explaining it: Persistent Volumes

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi

Above YAML will create a storage claim for MySQL. Apply it with command:

$ kubectl apply -f FILE_NAME.

Deployment

Create a YAML definition of a deployment from the official example and adjust it if there were any changes to names of the objects:

apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: mysql
    spec:
      containers:
      - image: mysql:5.6
        name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-password
              key: password
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim

Take a specific look on the part below, which is parsing secret password to the MySQL pod:

        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-password
              key: password

Apply it with command: $ kubectl apply -f FILE_NAME.

Service

What was missing in your the configuration was service objects. This objects allows communication with other pods, external traffic etc. Look at below example:

apiVersion: v1
kind: Service
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  ports:
    - port: 3306
  selector:
    app: wordpress
    tier: mysql
  clusterIP: None

This definition will create a object which will point to the MySQL pod.

It will create a DNS entry with the name of wordpress-mysql and IP address of the pod.

It will not expose it to external traffic as it's not needed.

Apply it with command: $ kubectl apply -f FILE_NAME.

Running WordPress

Persistent Volume Claim

As well as MySQL, WordPress require a dedicated space for storing the data. Create it with below example:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wp-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi

Apply it with command: $ kubectl apply -f FILE_NAME.

Deployment

Create YAML definition of WordPress as example below:

apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: frontend
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: frontend
    spec:
      containers:
      - image: wordpress:4.8-apache
        name: wordpress
        env:
        - name: WORDPRESS_DB_HOST
          value: wordpress-mysql
        - name: WORDPRESS_DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-password
              key: password
        ports:
        - containerPort: 80
          name: wordpress
        volumeMounts:
        - name: wordpress-persistent-storage
          mountPath: /var/www/html
      volumes:
      - name: wordpress-persistent-storage
        persistentVolumeClaim:
          claimName: wp-pv-claim

Take a specific look at:

        - name: WORDPRESS_DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-password
              key: password

This part will parse secret value to the deployment.

Below definition will tell WordPress where MySQL is located:

        - name: WORDPRESS_DB_HOST
          value: wordpress-mysql

Apply it with command: $ kubectl apply -f FILE_NAME.

Allowing external access

There are many different approaches for configuring external access to applications.

Minikube

Configuration could differ between different hypervisors.

For example Minikube can expose WordPress to external traffic with:

NodePort

apiVersion: v1
kind: Service
metadata:
  name: wordpress-nodeport 
spec:
  type: NodePort
  selector:
      app: wordpress
      tier: frontend
  ports:
  - name: wordpress-port
    protocol: TCP
    port: 80
    targetPort: 80

After applying this definition you will need to enter the minikube IP address with appropriate port to the web browser.

This port can be found with command: $ kubectl get svc wordpress-nodeport

Output of above command:

wordpress-nodeport   NodePort   10.76.9.15   <none>        80:30173/TCP   8s

In this case it is 30173.

LoadBalancer

In this case it will create NodePort also!

apiVersion: v1
kind: Service
metadata:
  name: wordpress-loadbalancer
  labels:
    app: wordpress
spec:
  ports:
    - port: 80
  selector:
    app: wordpress
    tier: frontend
  type: LoadBalancer

Ingress resource

Please refer to this link: Minikube: create-an-ingress-resource

Also you can refer to this Stack Overflow post

Kubeadm

With the Kubernetes clusters provided by kubeadm there are:

NodePort

The configuration process is the same as in minikube. The only difference is that it will create NodePort on each of every node in the cluster. After that you can enter IP address of any of the node with appropriate port. Be aware that you will neeed to be in the same network without firewall blocking your access.

LoadBalancer

You can create LoadBalancer object with the same YAML definition as in minikube. The problem is that with kubeadm provisioning on a bare metal cluster the LoadBalancer will not get IP address. The one of the options is: MetalLB

Ingress

Ingress resources share the same problem as LoadBalancer in kubeadm provisioned infrastructure. As above one of the options is: MetalLB.

Cloud Provisioned

There are many options which are strictly related to cloud that Kubernetes works on. Below is example for configuring Ingress resource with NGINX controller on GKE:

Apply both of the YAML definitions:

$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.27.1/deploy/static/mandatory.yaml
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.27.1/deploy/static/provider/cloud-generic.yaml

Apply NodePort definition from minikube

Create Ingress resource:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:
  - http:
      paths:
      - path: /
        backend:
          serviceName: wordpress-nodeport
          servicePort: wordpress-port

Apply it with command: $ kubectl apply -f FILE_NAME.

Check if Ingress resource got the address from cloud provider with command:

$ kubectl get ingress

The output should look like that:

NAME      HOSTS   ADDRESS         PORTS   AGE
ingress   *       XXX.XXX.XXX.X   80      26m

After entering the IP address from above command you should get: WordPress web browser first use

Cloud provisioned example can be used for kubeadm provisioned clusters with the MetalLB configured.

-- Dawid Kruk
Source: StackOverflow

1/15/2020

With your current setup you need to use wget http://10.233.92.7:8080/wp-admin/install.php from within the cluster i.e by performing kubectl exec into another pod because 10.233.92.7 IP is valid only within the cluster.

You should create a service for exposing your pod. Create a cluster IP type service(default) for accessing from within the cluster. If you want to access from outside the cluster i.e from your desktop then create a NodePort or LoadBalancer type service.

Other way to access the application from your desktop will be port forwarding. In this case you don't need to create a service.

Here is a tutorial for accessing pods using NodePort service. In this case your node need to have public ip.

-- Arghya Sadhu
Source: StackOverflow