docs: add Kubernetes CKS study notes
This commit is contained in:
126
kubernetes/level 3/task-1.md
Normal file
126
kubernetes/level 3/task-1.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# Assignment
|
||||
|
||||
There is an application that needs to be deployed on Kubernetes cluster under Apache web server. The Nautilus application development team has asked the DevOps team to deploy it. We need to develop a template as per requirements mentioned below:
|
||||
|
||||
|
||||
Create a namespace named as httpd-namespace-nautilus.
|
||||
|
||||
Create a deployment named as httpd-deployment-nautilus under newly created namespace. For the deployment use httpd image with latest tag only and remember to mention the tag i.e httpd:latest, and make sure replica counts are 2.
|
||||
|
||||
Create a service named as httpd-service-nautilus under same namespace to expose the deployment, nodePort should be 30004.
|
||||
|
||||
Note: The kubectl utility on the controlplane has been configured to work with the Kubernetes cluster.
|
||||
|
||||
# Solution
|
||||
|
||||
# Apache on Kubernetes — namespace + deployment + service (`nautilus`)
|
||||
|
||||
An httpd Deployment (2 replicas) exposed via a NodePort Service, all inside a dedicated namespace.
|
||||
One multi-document heredoc — no manifest file on disk.
|
||||
|
||||
## Apply (heredoc → kubectl)
|
||||
|
||||
```bash
|
||||
kubectl apply -f - <<'EOF'
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: httpd-namespace-nautilus
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: httpd-deployment-nautilus
|
||||
namespace: httpd-namespace-nautilus
|
||||
labels:
|
||||
app: httpd
|
||||
spec:
|
||||
replicas: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: httpd
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: httpd
|
||||
spec:
|
||||
containers:
|
||||
- name: httpd-container
|
||||
image: httpd:latest
|
||||
ports:
|
||||
- containerPort: 80
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: httpd-service-nautilus
|
||||
namespace: httpd-namespace-nautilus
|
||||
labels:
|
||||
app: httpd
|
||||
spec:
|
||||
type: NodePort
|
||||
selector:
|
||||
app: httpd
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
nodePort: 30004
|
||||
EOF
|
||||
|
||||
kubectl rollout status deployment/httpd-deployment-nautilus -n httpd-namespace-nautilus
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
### The heredoc apply pattern
|
||||
|
||||
- **`kubectl apply -f -`** reads from **stdin**; `---` separates the three documents, applied in
|
||||
order so the **Namespace** exists before the Deployment and Service land in it.
|
||||
- **`<<'EOF'` (delimiter quoted)** keeps the manifest literal — the right default for k8s YAML.
|
||||
|
||||
### Everything scoped to one namespace
|
||||
|
||||
All three objects carry `namespace: httpd-namespace-nautilus` (the Namespace defines it; the
|
||||
Deployment and Service reference it). Creating the namespace first in the same stream avoids a
|
||||
`namespaces "..." not found` error, and same-namespace scoping lets the Service select the
|
||||
deployment's pods by label directly.
|
||||
|
||||
### The Deployment
|
||||
|
||||
- **`name: httpd-deployment-nautilus`**, **`image: httpd:latest`** (tag stated explicitly),
|
||||
**`replicas: 2`** — all exactly as required.
|
||||
- **`containerPort: 80`** — Apache serves on 80 inside the container.
|
||||
- **`app: httpd`** label on the template — ties the Deployment to its pods and the Service to those
|
||||
pods. Container name `httpd-container` is a free choice.
|
||||
- **`selector.matchLabels: app: httpd`** equals the template labels — the Deployment↔pod link.
|
||||
|
||||
### The Service — targetPort 80
|
||||
|
||||
- **`type: NodePort`** exposes Apache outside the cluster.
|
||||
- **`selector: app: httpd`** targets the deployment's two pods by label and load-balances across
|
||||
them.
|
||||
- **Port mapping:**
|
||||
- `port: 80` — the Service's ClusterIP port.
|
||||
- **`targetPort: 80`** — the container port; must be 80 to reach Apache.
|
||||
- `nodePort: 30004` — the external port on each node, exactly as required (valid
|
||||
`30000–32767` range).
|
||||
|
||||
Path: `<node-ip>:30004` → Service `:80` → one of the two pods `:80`.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
# Both replicas running in the namespace
|
||||
kubectl get deployment httpd-deployment-nautilus -n httpd-namespace-nautilus
|
||||
kubectl get pods -n httpd-namespace-nautilus -l app=httpd
|
||||
|
||||
# Service on 30004 with two endpoints
|
||||
kubectl get service httpd-service-nautilus -n httpd-namespace-nautilus
|
||||
kubectl get endpoints httpd-service-nautilus -n httpd-namespace-nautilus
|
||||
```
|
||||
|
||||
Expected — deployment `READY 2/2`, both pods `Running`, `httpd-service-nautilus` NodePort
|
||||
`80:30004/TCP` with **two** endpoints, and Apache reachable at `<node-ip>:30004`.
|
||||
|
||||
> Everything is in `httpd-namespace-nautilus` — keep `-n httpd-namespace-nautilus` on every command.
|
||||
> If endpoints is empty, the service selector doesn't match the pod labels.
|
||||
0
kubernetes/level 3/task-10.md
Normal file
0
kubernetes/level 3/task-10.md
Normal file
0
kubernetes/level 3/task-11.md
Normal file
0
kubernetes/level 3/task-11.md
Normal file
263
kubernetes/level 3/task-2.md
Normal file
263
kubernetes/level 3/task-2.md
Normal file
@@ -0,0 +1,263 @@
|
||||
# Assignment
|
||||
|
||||
The Nautilus DevOps team wants to deploy a PHP website on a Kubernetes cluster. They plan to use Apache as the web server and MySQL for the database. The team has already gathered the requirements and now wants to make the website live. More details can be found below:
|
||||
|
||||
|
||||
|
||||
1) Create a ConfigMap named php-config containing the data variables_order = "EGPCS" for the php.ini file.
|
||||
|
||||
2) Create a Deployment named lamp-wp.
|
||||
|
||||
3) Within this Deployment, create two containers. The first container should be named httpd-php-container and utilize the image webdevops/php-apache:alpine-3-php7. The second container should be named mysql-container and use the image mysql:5.6. Mount the php-config ConfigMap in the httpd container at the location /opt/docker/etc/php/php.ini.
|
||||
|
||||
4) Note that secrets have already been created for the following MySQL-related values: MySQL root password, MySQL user, MySQL password, MySQL host, and MySQL database. These secrets are securely stored and can be accessed as needed.
|
||||
|
||||
5) Add the following environment variables for both containers: MYSQL_ROOT_PASSWORD, MYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORD, and MYSQL_HOST. Ensure that their values are sourced from the secrets created earlier. Please utilize the env field (do not use envFrom) to define the name-value pairs of the environment variables.
|
||||
|
||||
6) Create a NodePort type Service named lamp-service to expose the web application, specifying the NodePort as 30008.
|
||||
|
||||
7) Create a Service for MySQL named mysql-service, ensuring its port is set to 3306.
|
||||
|
||||
8) A file named /tmp/index.php is available on the jump-host.
|
||||
|
||||
a) Copy this file into the httpd container under the Apache document root at /app, replacing the dummy values for MySQL-related variables with the corresponding environment variables you have defined. Ensure that the MySQL-related details are not hardcoded in this file, and utilize environment variables to retrieve those values.
|
||||
|
||||
b) You should be able to access the index.php file through NodePort 30008. Upon accessing this page, the message Connected successfully should be displayed.
|
||||
|
||||
Note: The kubectl utility on the jump-host has been configured to work with the Kubernetes cluster.
|
||||
|
||||
# Solution
|
||||
|
||||
# Build LAMP WordPress Stack — `lamp-wp` + `php-config` + services
|
||||
|
||||
A two-container LAMP pod (Apache/PHP + MySQL), a ConfigMap for `php.ini`, two Services, and a PHP
|
||||
page wired to the DB via env vars. Manifests applied via a multi-document heredoc, then the file
|
||||
copied in.
|
||||
|
||||
## Step 0 — Confirm the secret names and keys (do this first)
|
||||
|
||||
The env vars source from pre-created Secrets. Verify their exact names/keys and adjust the manifest
|
||||
if yours differ:
|
||||
|
||||
```bash
|
||||
kubectl get secrets
|
||||
for s in mysql-root-pass mysql-user-pass mysql-host mysql-db-url; do
|
||||
echo "== $s =="; kubectl get secret "$s" -o jsonpath='{.data}' | tr ',' '\n'
|
||||
done
|
||||
```
|
||||
|
||||
This solution uses the standard mapping:
|
||||
|
||||
| Env var | Secret name | Key |
|
||||
|---------|-------------|-----|
|
||||
| `MYSQL_ROOT_PASSWORD` | `mysql-root-pass` | `password` |
|
||||
| `MYSQL_DATABASE` | `mysql-db-url` | `database` |
|
||||
| `MYSQL_USER` | `mysql-user-pass` | `username` |
|
||||
| `MYSQL_PASSWORD` | `mysql-user-pass` | `password` |
|
||||
| `MYSQL_HOST` | `mysql-host` | `host` |
|
||||
|
||||
## Step 1 — Apply ConfigMap + Deployment + Services (heredoc)
|
||||
|
||||
```bash
|
||||
kubectl apply -f - <<'EOF'
|
||||
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: lamp
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: lamp
|
||||
tier: frontend
|
||||
strategy:
|
||||
type: Recreate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: lamp
|
||||
tier: frontend
|
||||
spec:
|
||||
containers:
|
||||
- name: httpd-php-container
|
||||
image: webdevops/php-apache:alpine-3-php7
|
||||
ports:
|
||||
- containerPort: 80
|
||||
env:
|
||||
- name: MYSQL_ROOT_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef: { name: mysql-root-pass, key: password }
|
||||
- name: MYSQL_DATABASE
|
||||
valueFrom:
|
||||
secretKeyRef: { name: mysql-db-url, key: database }
|
||||
- name: MYSQL_USER
|
||||
valueFrom:
|
||||
secretKeyRef: { name: mysql-user-pass, key: username }
|
||||
- name: MYSQL_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef: { name: mysql-user-pass, key: password }
|
||||
- name: MYSQL_HOST
|
||||
valueFrom:
|
||||
secretKeyRef: { name: mysql-host, key: host }
|
||||
volumeMounts:
|
||||
- name: php-config-volume
|
||||
mountPath: /opt/docker/etc/php/php.ini
|
||||
subPath: php.ini
|
||||
- name: mysql-container
|
||||
image: mysql:5.6
|
||||
ports:
|
||||
- containerPort: 3306
|
||||
env:
|
||||
- name: MYSQL_ROOT_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef: { name: mysql-root-pass, key: password }
|
||||
- name: MYSQL_DATABASE
|
||||
valueFrom:
|
||||
secretKeyRef: { name: mysql-db-url, key: database }
|
||||
- name: MYSQL_USER
|
||||
valueFrom:
|
||||
secretKeyRef: { name: mysql-user-pass, key: username }
|
||||
- name: MYSQL_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef: { name: mysql-user-pass, key: password }
|
||||
- name: MYSQL_HOST
|
||||
valueFrom:
|
||||
secretKeyRef: { name: mysql-host, key: host }
|
||||
volumes:
|
||||
- name: php-config-volume
|
||||
configMap:
|
||||
name: php-config
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: lamp-service
|
||||
labels:
|
||||
app: lamp
|
||||
spec:
|
||||
type: NodePort
|
||||
selector:
|
||||
app: lamp
|
||||
tier: frontend
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
nodePort: 30008
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: mysql-service
|
||||
labels:
|
||||
app: lamp
|
||||
spec:
|
||||
selector:
|
||||
app: lamp
|
||||
tier: frontend
|
||||
ports:
|
||||
- port: 3306
|
||||
targetPort: 3306
|
||||
EOF
|
||||
|
||||
kubectl rollout status deployment/lamp-wp
|
||||
```
|
||||
|
||||
## Step 2 — Point index.php at the env vars (no hardcoded DB values)
|
||||
|
||||
Edit `/tmp/index.php` on the jump-host so the MySQL values come from `getenv(...)` instead of dummy
|
||||
literals. The corrected connection block:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$dbname = getenv('MYSQL_DATABASE');
|
||||
$dbuser = getenv('MYSQL_USER');
|
||||
$dbpass = getenv('MYSQL_PASSWORD');
|
||||
$dbhost = getenv('MYSQL_HOST');
|
||||
|
||||
$conn = mysqli_connect($dbhost, $dbuser, $dbpass, $dbname);
|
||||
if (!$conn) {
|
||||
die("Connection failed: " . mysqli_connect_error());
|
||||
}
|
||||
echo "Connected successfully";
|
||||
?>
|
||||
```
|
||||
|
||||
Keep the rest of the file as-is; only swap the four dummy assignments for the `getenv()` calls.
|
||||
|
||||
## Step 3 — Copy the file into the httpd container's document root (`/app`)
|
||||
|
||||
```bash
|
||||
POD=$(kubectl get pod -l app=lamp -o jsonpath='{.items[0].metadata.name}')
|
||||
|
||||
kubectl cp /tmp/index.php "$POD":/app/index.php -c httpd-php-container
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
### ConfigMap → php.ini via subPath
|
||||
|
||||
`php-config` holds one key, `php.ini`, whose value is the directive `variables_order = "EGPCS"`.
|
||||
It's mounted into the httpd container with **`subPath: php.ini`** at
|
||||
`/opt/docker/etc/php/php.ini`. `subPath` mounts a **single file** into an existing directory rather
|
||||
than replacing the whole directory — essential here, since `/opt/docker/etc/php/` contains other
|
||||
files that must stay. Without `subPath`, the mount would hide everything else in that directory.
|
||||
|
||||
### Two containers, one pod
|
||||
|
||||
Apache/PHP and MySQL run as two containers in the **same pod**, sharing the pod's network namespace.
|
||||
Both get the identical five env vars, each sourced from a Secret via **`valueFrom.secretKeyRef`** —
|
||||
using the `env` field per the requirement (not `envFrom`, which would bulk-import a whole Secret
|
||||
under its own key names). The MySQL container reads `MYSQL_*` to initialize the database and user;
|
||||
the httpd container reads the same values so PHP can connect with matching credentials.
|
||||
|
||||
### The two Services
|
||||
|
||||
- **`lamp-service`** — `NodePort`, `targetPort: 80` (Apache's port), `nodePort: 30008`. This is the
|
||||
public entry point: `<node-ip>:30008` → Apache `:80`.
|
||||
- **`mysql-service`** — default ClusterIP, `port: 3306`. It gives MySQL a stable in-cluster DNS name
|
||||
(`mysql-service`) so the app can reach the DB by name. Both Services select the same pod
|
||||
(`app: lamp, tier: frontend`); each routes to the port relevant to its container.
|
||||
|
||||
Whatever the `mysql-host` Secret contains (e.g. `mysql-service` or `localhost`) is what
|
||||
`MYSQL_HOST`/`$dbhost` becomes — so the app connects through the correct host without hardcoding it.
|
||||
|
||||
### Why the PHP file uses getenv()
|
||||
|
||||
Requirement 8a forbids hardcoding DB details. `getenv('MYSQL_HOST')` etc. pull the values from the
|
||||
container's environment (the Secret-sourced env vars) at request time. So credentials live only in
|
||||
Secrets and env — never in the file — and the page renders `Connected successfully` once the
|
||||
connection succeeds. The webdevops php-apache image serves from **`/app`**, so `index.php` copied
|
||||
there is reachable at the web root.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
# Pod running with both containers
|
||||
kubectl get pods -l app=lamp # READY 2/2
|
||||
|
||||
# php.ini mounted correctly
|
||||
kubectl exec "$POD" -c httpd-php-container -- cat /opt/docker/etc/php/php.ini
|
||||
|
||||
# Services present
|
||||
kubectl get svc lamp-service mysql-service
|
||||
|
||||
# The page returns the success message
|
||||
curl -s http://<node-ip>:30008/index.php
|
||||
```
|
||||
|
||||
Expected — pod `READY 2/2`, `php.ini` showing `variables_order = "EGPCS"`, both services present,
|
||||
and the page printing **`Connected successfully`** at `<node-ip>:30008/index.php`.
|
||||
|
||||
> If it shows a connection error instead, MySQL 5.6 may still be initializing (first boot is slow) —
|
||||
> retry after a minute. If it persists, re-check that the Secret names/keys in Step 0 match the
|
||||
> manifest and that `mysql-host` resolves to a reachable host.
|
||||
139
kubernetes/level 3/task-3.md
Normal file
139
kubernetes/level 3/task-3.md
Normal file
@@ -0,0 +1,139 @@
|
||||
# Assignment
|
||||
|
||||
There are some applications that need to be deployed on Kubernetes cluster and these apps have some pre-requisites where some configurations need to be changed before deploying the app container. Some of these changes cannot be made inside the images so the DevOps team has come up with a solution to use init containers to perform these tasks during deployment. Below is a sample scenario that the team is going to test first.
|
||||
|
||||
|
||||
|
||||
Create a Deployment named as ic-deploy-devops.
|
||||
|
||||
|
||||
Configure spec as replicas should be 1, labels app should be ic-devops, template's metadata lables app should be the same ic-devops.
|
||||
|
||||
|
||||
The initContainers should be named as ic-msg-devops, use image fedora with latest tag and use command '/bin/bash', '-c' and 'echo Init Done - Welcome to xFusionCorp Industries > /ic/media'. The volume mount should be named as ic-volume-devops and mount path should be /ic.
|
||||
|
||||
|
||||
Main container should be named as ic-main-devops, use image fedora with latest tag and use command '/bin/bash', '-c' and 'while true; do cat /ic/media; sleep 5; done'. The volume mount should be named as ic-volume-devops and mount path should be /ic.
|
||||
|
||||
|
||||
Volume to be named as ic-volume-devops and it should be an emptyDir type.
|
||||
|
||||
|
||||
Note: The kubectl utility on the jump-host has been configured to work with the Kubernetes cluster.
|
||||
|
||||
# Solution
|
||||
|
||||
# Deployment with Init Container — `ic-deploy-devops`
|
||||
|
||||
An init container writes a message to a shared `emptyDir` volume; the main container then reads it
|
||||
in a loop. This is the canonical init-container pattern. Applied inline via a heredoc — no manifest
|
||||
file on disk.
|
||||
|
||||
## Apply (heredoc → kubectl)
|
||||
|
||||
```bash
|
||||
kubectl apply -f - <<'EOF'
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: ic-deploy-devops
|
||||
labels:
|
||||
app: ic-devops
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: ic-devops
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: ic-devops
|
||||
spec:
|
||||
initContainers:
|
||||
- name: ic-msg-devops
|
||||
image: fedora:latest
|
||||
command:
|
||||
- /bin/bash
|
||||
- -c
|
||||
- "echo Init Done - Welcome to xFusionCorp Industries > /ic/media"
|
||||
volumeMounts:
|
||||
- name: ic-volume-devops
|
||||
mountPath: /ic
|
||||
containers:
|
||||
- name: ic-main-devops
|
||||
image: fedora:latest
|
||||
command:
|
||||
- /bin/bash
|
||||
- -c
|
||||
- "while true; do cat /ic/media; sleep 5; done"
|
||||
volumeMounts:
|
||||
- name: ic-volume-devops
|
||||
mountPath: /ic
|
||||
volumes:
|
||||
- name: ic-volume-devops
|
||||
emptyDir: {}
|
||||
EOF
|
||||
|
||||
kubectl rollout status deployment/ic-deploy-devops
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
### The heredoc apply pattern
|
||||
|
||||
- **`kubectl apply -f -`** reads from **stdin**; nothing written to disk.
|
||||
- **`<<'EOF'` (delimiter quoted)** keeps the manifest literal — the right default for k8s YAML.
|
||||
|
||||
### Init container vs. main container — the ordering guarantee
|
||||
|
||||
This is a **classic** init container (under `initContainers`, no `restartPolicy` override), which
|
||||
behaves very differently from the main container:
|
||||
|
||||
- **`ic-msg-devops` (init)** runs **first, to completion**, before any main container starts. It
|
||||
`echo`s the message into `/ic/media` and exits `0`. Because it's a one-shot task that finishes,
|
||||
a classic init container is exactly right here — it does setup work, then gets out of the way.
|
||||
- **`ic-main-devops` (main)** starts **only after** the init container succeeds. It then loops,
|
||||
`cat`-ing `/ic/media` every 5 seconds. The `while true` keeps it running so the pod stays up.
|
||||
|
||||
The sequencing is guaranteed by Kubernetes: init containers complete before app containers begin.
|
||||
That's what makes the pattern work — the file is written before the main container ever tries to
|
||||
read it.
|
||||
|
||||
### The shared `emptyDir` volume
|
||||
|
||||
- **`ic-volume-devops` (`emptyDir: {}`)** is declared once and mounted at **`/ic` in both
|
||||
containers**. `emptyDir` is created empty when the pod starts and shared by all its containers, so
|
||||
the init container's write to `/ic/media` is visible to the main container at the same path. This
|
||||
is the hand-off mechanism: init writes, main reads, through shared storage.
|
||||
|
||||
Both `volumeMounts` reference the same volume name (`ic-volume-devops`) at the same path — that's
|
||||
what ties them to one storage location.
|
||||
|
||||
### Why the commands need `/bin/bash -c`
|
||||
|
||||
Each command is a shell one-liner (a redirect for the init, a loop for the main), so both run via
|
||||
`/bin/bash -c`. The main container's `while true` loop is what keeps it in `Running` state — without
|
||||
a long-running process, the `fedora` container would exit immediately and the pod would crash-loop.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
# Deployment ready
|
||||
kubectl get deployment ic-deploy-devops
|
||||
kubectl get pods -l app=ic-devops
|
||||
|
||||
# Init container completed (check pod init status)
|
||||
kubectl get pod -l app=ic-devops \
|
||||
-o jsonpath='{.items[0].status.initContainerStatuses[0].state}{"\n"}'
|
||||
|
||||
# Main container is printing the message from the shared volume
|
||||
kubectl logs -l app=ic-devops -c ic-main-devops --tail=3
|
||||
```
|
||||
|
||||
Expected — deployment `READY 1/1`, the init container state showing `terminated`/`reason:
|
||||
Completed`, and the main container's logs repeatedly printing
|
||||
`Init Done - Welcome to xFusionCorp Industries`.
|
||||
|
||||
> If the pod is stuck in `Init:0/1`, the init container hasn't completed — check
|
||||
> `kubectl logs -l app=ic-devops -c ic-msg-devops`. Unlike a native sidecar, a classic init
|
||||
> container here is *meant* to finish, and it does (the echo exits immediately).
|
||||
16
kubernetes/level 3/task-4.md
Normal file
16
kubernetes/level 3/task-4.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# Assignment
|
||||
|
||||
The Nautilus DevOps team is working on a Kubernetes template to deploy a web application on the cluster. There are some requirements to create/use persistent volumes to store the application code, and the template needs to be designed accordingly. Please find more details below:
|
||||
|
||||
|
||||
Create a PersistentVolume named as pv-xfusion. Configure the spec as storage class should be manual, set capacity to 4Gi, set access mode to ReadWriteOnce, volume type should be hostPath and set path to /mnt/itadmin (this directory is already created, you might not be able to access it directly, so you need not to worry about it).
|
||||
|
||||
Create a PersistentVolumeClaim named as pvc-xfusion. Configure the spec as storage class should be manual, request 2Gi of the storage, set access mode to ReadWriteOnce.
|
||||
|
||||
Create a pod named as pod-xfusion, mount the persistent volume you created with claim name pvc-xfusion at document root of the web server, the container within the pod should be named as container-xfusion using image nginx with latest tag only (remember to mention the tag i.e nginx:latest).
|
||||
|
||||
Create a node port type service named web-xfusion using node port 30008 to expose the web server running within the pod.
|
||||
|
||||
Note: The kubectl utility on the jump-host has been configured to work with the Kubernetes cluster.
|
||||
|
||||
# Solution
|
||||
0
kubernetes/level 3/task-5.md
Normal file
0
kubernetes/level 3/task-5.md
Normal file
0
kubernetes/level 3/task-6.md
Normal file
0
kubernetes/level 3/task-6.md
Normal file
0
kubernetes/level 3/task-7.md
Normal file
0
kubernetes/level 3/task-7.md
Normal file
0
kubernetes/level 3/task-8.md
Normal file
0
kubernetes/level 3/task-8.md
Normal file
0
kubernetes/level 3/task-9.md
Normal file
0
kubernetes/level 3/task-9.md
Normal file
Reference in New Issue
Block a user