Deploy Lamp Stack on Kubernetes Cluster - ConfigMap Mount Error

/tmp/index.php on jump host is incorrect. This is what I see.

It is missing ?> towards the end which took me a while to figure out.

I get 502 bad gateway error, I’ve got all resources up and running, don’t see anything in logs. Also index.php file disappears on container every couple of minutes and I’m thrown out of the container with error 137.

Unable to upload all code files, new user limit.

First, you should use variables in php file.

$dbname = $_ENV["MYSQL_DATABASE"];
$dbuser = $_ENV["MYSQL_USER"];
$dbpass = $_ENV["MYSQL_PASSWORD"];
$dbhost = $_ENV["MYSQL_HOST"];

Second, to copy to particular container in pod, you should use something like that:
kubectl cp /tmp/index.php lamp-wp-7d46b7c945-zsh8d:/app/index.php -c httpd-php-container
Same, when you like to exec to it:
kubectl exec -it lamp-wp-7d46b7c945-zsh8d -c httpd-php-container -- /bin/sh
And try to use this yaml for lamp:

apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
type: Opaque
data:
  mysql-root-password: cm9vdHBhc3M=
  mysql-database: c3FsYmFzZQ==
  mysql-user: dXNlcg==
  mysql-password: dXNlcnBhc3M=
  mysql-host: bXlzcWwtY29udGFpbmVy
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: php-config
data:
  php.ini: |
    variables_order="EGPCS"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: lamp-wp
  labels:
    app: httpd 
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpd 
  template:
    metadata:
      labels:
        app: httpd 
    spec:
      hostname: mysql-container
      containers:
        - name: httpd-php-container
          image: webdevops/php-apache:alpine-3-php7
          ports:
            - containerPort: 80
          env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: mysql-root-password
            - name: MYSQL_DATABASE
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: mysql-database
            - name: MYSQL_USER
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: mysql-user
            - name: MYSQL_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: mysql-password
            - name: MYSQL_HOST
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: mysql-host
          volumeMounts:
          - name: php-config
            mountPath: /opt/docker/etc/php/php.ini
            subPath: php.ini
        - name: mysql-container
          image: mysql:5.6
          env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: mysql-root-password
            - name: MYSQL_DATABASE
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: mysql-database
            - name: MYSQL_USER
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: mysql-user
            - name: MYSQL_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: mysql-password
            - name: MYSQL_HOST
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: mysql-host
          ports:
            - containerPort: 3306
      volumes:
        - name: php-config
          configMap:
            name: php-config
---
apiVersion: v1
kind: Service
metadata:
  name: lamp-service
spec:
  selector:
    app: httpd 
  type: NodePort
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
      nodePort: 30008
---
apiVersion: v1
kind: Service
metadata:
  name: mysql-service
spec:
  selector:
    app: httpd 
  ports:
    - protocol: TCP
      port: 3306
      targetPort: 3306  

I tried with same code in the past with no luck. Supplied sql values you shared and that didn’t help. I’ve been at this for a while now, not sure what I’m missing.

thor@jump_host ~$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/lamp-wp-5466bc994d-n4gm4 2/2 Running 0 7m35s

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 443/TCP 35m
service/lamp-service NodePort 10.96.89.33 80:30008/TCP 14m
service/mysql-service ClusterIP 10.96.23.175 3306/TCP 14m

NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/lamp-wp 1/1 1 1 7m35s

NAME DESIRED CURRENT READY AGE
replicaset.apps/lamp-wp-5466bc994d 1 1 1 7m35s

/app # cat index.php

<?php $dbname = $_ENV["MYSQL_DATABASE"]; $dbuser = $_ENV["MYSQL_USER"]; $dbpass = $_ENV["MYSQL_PASSWORD"]; $dbhost = $_ENV["MYSQL_HOST"]; $connect = mysqli_connect($dbhost, $dbuser, $dbpass) or die("Unable to Connect to '$dbhost'"); $test_query = "SHOW TABLES FROM $dbname"; $result = mysqli_query($test_query); if ($result->connect_error) { die("Connection failed: " . $conn->connect_error); } echo "Connected successfully"; ?>

Also, can you advise why I don’t see code block button on the top like you guys do? My format disappears as soon as I paste the code in the reply window.

You can type 3 backticks ``` on its own line to start code block, then the text you want formatted, then type ``` again on a new line underneath to close it

```
this is code block
```

Will make

this is code block

Thank you. I still see error 502.

Below is my code.

apiVersion: v1
kind: ConfigMap
metadata:
  name: php-config
data:
  php.ini: |
    variables_order = "EGPCS"
apiVersion: v1
kind: Secret
metadata:
  name: sqlsecrets
type: Opaque
data:
  MYSQL_ROOT_PASSWORD: cm9vdHBhc3M=
  MYSQL_DATABASE: c3FsYmFzZQ==
  MYSQL_USER: dXNlcg==
  MYSQL_PASSWORD: dXNlcnBhc3M=
  MYSQL_HOST: bXlzcWwtY29udGFpbmVy
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: lamp-wp
  name: lamp-wp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: lamp-wp
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: lamp-wp
    spec:
      containers:
        - name: httpd-php-container
          image: webdevops/php-apache:alpine-3-php7
          command: ["sleep","600"]
          ports:
          - containerPort: 80
          volumeMounts:
          - name: php-config-volume
            mountPath: /opt/docker/etc/php
          env:
          - name: MYSQL_ROOT_PASSWORD
            valueFrom:
              secretKeyRef:
                name: sqlsecrets
                key: MYSQL_ROOT_PASSWORD
          - name: MYSQL_PASSWORD
            valueFrom:
              secretKeyRef:
                name: sqlsecrets
                key: MYSQL_PASSWORD
          - name: MYSQL_DATABASE
            valueFrom:
              secretKeyRef:
                name: sqlsecrets
                key: MYSQL_DATABASE
          - name: MYSQL_USER
            valueFrom:
              secretKeyRef:
                name: sqlsecrets
                key: MYSQL_USER
          - name: MYSQL_HOST
            valueFrom:
              secretKeyRef:
                name: sqlsecrets
                key: MYSQL_HOST

        - name: mysql-container
          image: mysql:5.6
          ports:
          - containerPort: 3306
          env:
          - name: MYSQL_ROOT_PASSWORD
            valueFrom:
              secretKeyRef:
                name: sqlsecrets
                key: MYSQL_ROOT_PASSWORD
          - name: MYSQL_PASSWORD
            valueFrom:
              secretKeyRef:
                name: sqlsecrets
                key: MYSQL_PASSWORD
          - name: MYSQL_DATABASE
            valueFrom:
              secretKeyRef:
                name: sqlsecrets
                key: MYSQL_DATABASE
          - name: MYSQL_USER
            valueFrom:
              secretKeyRef:
                name: sqlsecrets
                key: MYSQL_USER
          - name: MYSQL_HOST
            valueFrom:
              secretKeyRef:
                name: sqlsecrets
                key: MYSQL_HOST			  
      volumes:
        - name: php-config-volume
          configMap:
            name: php-config
apiVersion: v1
kind: Service
metadata:
  name: lamp-service
spec:
  type: NodePort
  selector:
    app: lamp-wp
  ports:
    - protocol: TCP
      port: 80         # The port on the service (Cluster IP)
      targetPort: 80   # The port on the pods
      nodePort: 30008  # The static port exposed on each node (you can specify your desired port)
apiVersion: v1
kind: Service
metadata:
  name: mysql-service
spec:
  selector:
    app: lamp-wp
  ports:
    - protocol: TCP
      port: 3306        # The port on the service (Cluster IP)
      targetPort: 3306   # The port on the pods
<?php
$dbname = $_ENV["MYSQL_DATABASE"];
$dbuser = $_ENV["MYSQL_USER"];
$dbpass = $_ENV["MYSQL_PASSWORD"];
$dbhost = $_ENV["MYSQL_HOST"];

$connect = mysqli_connect($dbhost, $dbuser, $dbpass) or die("Unable to Connect to '$dbhost'");

$test_query = "SHOW TABLES FROM $dbname";
$result = mysqli_query($test_query);

if ($result->connect_error) {
   die("Connection failed: " . $conn->connect_error);
}
  echo "Connected successfully"; 
  
?>
thor@jump_host ~$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/lamp-wp-5466bc994d-n4gm4 2/2 Running 0 7m35s

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 443/TCP 35m
service/lamp-service NodePort 10.96.89.33 80:30008/TCP 14m
service/mysql-service ClusterIP 10.96.23.175 3306/TCP 14m

NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/lamp-wp 1/1 1 1 7m35s

NAME DESIRED CURRENT READY AGE
replicaset.apps/lamp-wp-5466bc994d 1 1 1 7m35s

Try to add subPath: php.ini in volumeMounts:

          volumeMounts:
          - name: php-config
            mountPath: /opt/docker/etc/php/php.ini
            subPath: php.ini

And try to add hostname line. Sometimes I have problems with hostname for database container, so I add this line.

Error restarting httpd-php-container when I add subPath.

  Warning  Failed     3s (x4 over 59s)  kubelet            Error: failed to create containerd task: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error mounting "/var/lib/kubelet/pods/60929f3c-1398-45b9-901f-f28b21f1878b/volume-subpaths/php-config-volume/httpd-php-container/0" to rootfs at "/opt/docker/etc/php": mount /var/lib/kubelet/pods/60929f3c-1398-45b9-901f-f28b21f1878b/volume-subpaths/php-config-volume/httpd-php-container/0:/opt/docker/etc/php (via /proc/self/fd/6), flags: 0x5001: not a directory: unknown
  Normal   Pulled     3s (x3 over 45s)  kubelet            Container image "webdevops/php-apache:alpine-3-php7" already present on machine
  Warning  BackOff    2s (x5 over 44s)  kubelet            Back-off restarting failed container httpd-php-container in pod lamp-wp-56b5cf66d8-5v9rc_default(60929f3c-1398-45b9-901f-f28b21f1878b)

Hostname for mysql-container is set to pod name. Are you referring to configuring mysql hostname with in mysql-container using “mysql -h” command?

Do not use subPath. It will not mount.

We already proved the other day how to mount the file. Pod is not failing due to that. It is something else.

Is it this question?

image

Nope, From Level 3 -

Right. I have now been through this and here is the solution.

#1

Create configmap

thor@jump_host ~$ echo 'variables_order = "EGPCS"' > php.ini
thor@jump_host ~$ k create cm php-config --from-file php.ini

#2/#3

thor@jump_host ~$ k create deployment lamp-wp --image webdevops/php-apache:alpine-3-php7 --dry-run=client -o yaml > lamp-wp.yaml
thor@jump_host ~$ vi lamp-wp.yaml 

Now we have to be careful how we mount php.ini. We are putting it into a directory that already exists and contains files and folders, so if we use a simple mount we are going to knock out all the other stuff.
We need to use a subPath mount, AND extra syntax in the volume declaration.

While we are here, also put in the mysql container.

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: lamp-wp
  name: lamp-wp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: lamp-wp
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: lamp-wp
    spec:
      volumes:
      - name: ini
        configMap:
          name: php-config
          items:            #<- This extra syntax to make subPath work properly
          - key: php.ini
            path: php.ini
      containers:
      - image: webdevops/php-apache:alpine-3-php7
        name: httpd-php-container
        volumeMounts:
        - name: ini
          mountPath: /opt/docker/etc/php/php.ini
          subPath: php.ini
      - image: mysql:5.6
        name: mysql-container

#4

CAREFUL - There is a curveball in this one! We cannot use just anything for MYSQL_HOST or the database will not be able to be connected to. Before creating the secret see task #7

thor@jump_host ~$ k create secret generic mysql-config --from-literal MYSQL_ROOT_PASSWORD=paswd --from-literal MYSQL_DATABASE=lampdb --from-literal MYSQL_USER=thor --from-literal MYSQL_PASSWORD=mjolnir123 --from-literal MYSQL_HOST=mysql-service

#5

Mount the secret’s environment variables. Note that I have used an alias/anchor combination here both for less typing and to avoid errors in duplicating the variables to both containers. This should now be the final edit to the deployment YAML

thor@jump_host ~$ vi lamp-wp.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: lamp-wp
  name: lamp-wp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: lamp-wp
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: lamp-wp
    spec:
      volumes:
      - name: ini
        configMap:
          name: php-config
          items:            #<- This extra syntax to make subPath work properly
          - key: php.ini
            path: php.ini
      containers:
      - image: webdevops/php-apache:alpine-3-php7
        name: httpd-php-container
        env: &environment               #<- ANCHOR
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-config
              key: MYSQL_ROOT_PASSWORD
        - name: MYSQL_DATABASE
          valueFrom:
            secretKeyRef:
              name: mysql-config
              key: MYSQL_DATABASE
        - name: MYSQL_USER
          valueFrom:
            secretKeyRef:
              name: mysql-config
              key: MYSQL_USER
        - name: MYSQL_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-config
              key: MYSQL_PASSWORD
        - name: MYSQL_HOST
          valueFrom:
            secretKeyRef:
              name: mysql-config
              key: MYSQL_HOST
        volumeMounts:
        - name: ini
          mountPath: /opt/docker/etc/php/php.ini
          subPath: php.ini
      - image: mysql:5.6
        name: mysql-container
        env: *environment               #<- ALIAS (all environment beneath ANCHOR will be repeated here)

#6

Create nodeport service. First run up the deployment that we have so far so we can use imperative commands to create the services

Spin up the deployment - it should run fine.

thor@jump_host ~$ k create -f lamp-wp.yaml

Create YAML file for nodePort service

thor@jump_host ~$ k expose deployment lamp-wp --port 80 --target-port 80 --type NodePort --name lamp-service --dry-run=client -o yaml > lamp-service.yaml

Edit in the correct nodeport

thor@jump_host ~$ vi lamp-service.yaml 
apiVersion: v1
kind: Service
metadata:
  labels:
    app: lamp-wp
  name: lamp-service
spec:
  ports:
  - port: 80
    protocol: TCP 
    targetPort: 80
    nodePort: 30008  #<- Add this
  selector:
    app: lamp-wp
  type: NodePort

Create service

k create -f lamp-service.yaml

#7

Create mysql-service

thor@jump_host ~$ k expose deployment lamp-wp --port 3306 --target-port 3306 --type ClusterIP --name mysql-service
service/mysql-service exposed

No need to create a YAML file for this service, since we don’t need to make additional edits to a ClusterIP service.

#8

Sort out index.php and place in the container

#8a

thor@jump_host ~$ cp /tmp/index.php .
thor@jump_host ~$ vi index.php 

Edit it to look like this

<?php
$dbname = getenv('MYSQL_DATABASE');
$dbuser = getenv('MYSQL_USER');
$dbpass = getenv('MYSQL_PASSWORD');
$dbhost = getenv('MYSQL_HOST');

$connect = mysqli_connect($dbhost, $dbuser, $dbpass) or die("Unable to Connect to '$dbhost'");

$test_query = "SHOW TABLES FROM $dbname";
$result = mysqli_query($test_query);

if ($result->connect_error) {
   die("Connection failed: " . $conn->connect_error);
}
  echo "Connected successfully";
?>

Now copy it into container

thor@jump_host ~$ k get po
NAME                       READY   STATUS    RESTARTS   AGE
lamp-wp-78cfc8c984-vsjc5   2/2     Running   0          18s

Note pod name. We will need it for the next command

k cp -c httpd-php-container index.php lamp-wp-78cfc8c984-vsjc5:/app/index.php

#8b Test it.

image

Thank you, its working now.

I believe the task instructions should be updated for mysql secrets. Choosing random values for mysql parameters doesn’t work.

This is a level 3 task, right?

I spotted immediately that a random value for MYSQL_HOST is not going to work - and no I didn’t have the solution in front of me, I had to work it out too. I think at level 3, people are kind of expected to draw the same conclusion. Hence my statement for #4 above. A level 1 task might explicitly tell you to use the service you create as the mysql host.

The other values indeed can be whatever you want, because the startup for the mysql container will configure them into the mysql server configuration.

@Alistair_KodeKloud

Noted.

I’m still learning, and hence it took me a lot longer to figure that one out. And this is the main reason for subscribing to KodeKloud Engineer, to practice different scenarios and learn hands on. Now I won’t forget. Appreciate you spending time to help me out on this.

mysql container keep crashing
@Alistair_KodeKloud

Hi @Sandra-Konotey
I have given the solution to this challenge further up in this thread. Please follow it carefully.

Can you elaborate on this more? why wouldnt a random value work?

update: I think i figured this out but would love confirmation.

When you need to connect to a service (like mysql in this case) you use the service’s “address”. This is either an IP address or a DNS name.

If you needed to go and visit somebody, you would ask for their address first and then go there. You would not pick an address at random, turn up at this address and hope it was the person you intended to visit.

The only reason the other values are random is because the mysql instance is not yet intialized, and these values are being used to create a new database and set the new username and password in the mysql server.

Were the mysql server to be pre-existing then all the values would have to be clearly defined since it would be expecting known credentials and the name of an existing database in the server.