惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Full Disclosure
WordPress大学
WordPress大学
小众软件
小众软件
Cloudbric
Cloudbric
AWS News Blog
AWS News Blog
腾讯CDC
量子位
人人都是产品经理
人人都是产品经理
大猫的无限游戏
大猫的无限游戏
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
V
Vulnerabilities – Threatpost
Scott Helme
Scott Helme
Hugging Face - Blog
Hugging Face - Blog
博客园_首页
C
CXSECURITY Database RSS Feed - CXSecurity.com
The Hacker News
The Hacker News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
IT之家
IT之家
Jina AI
Jina AI
Attack and Defense Labs
Attack and Defense Labs
S
SegmentFault 最新的问题
Simon Willison's Weblog
Simon Willison's Weblog
The Cloudflare Blog
阮一峰的网络日志
阮一峰的网络日志
T
Tailwind CSS Blog
Last Week in AI
Last Week in AI
博客园 - 【当耐特】
Google Online Security Blog
Google Online Security Blog
美团技术团队
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
Visual Studio Blog
罗磊的独立博客
L
LINUX DO - 最新话题
博客园 - Franky
博客园 - 叶小钗
Apple Machine Learning Research
Apple Machine Learning Research
The Last Watchdog
The Last Watchdog
J
Java Code Geeks
AI
AI
C
Cisco Blogs
酷 壳 – CoolShell
酷 壳 – CoolShell
C
Cyber Attacks, Cyber Crime and Cyber Security
Cisco Talos Blog
Cisco Talos Blog
博客园 - 三生石上(FineUI控件)
雷峰网
雷峰网
Help Net Security
Help Net Security
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
云风的 BLOG
云风的 BLOG
I
Intezer
S
Securelist

Ogenki

Self-hosted LLM stack: a solid foundation for an open-weight platform built to evolve A few months with `Claude Code`: tips and workflows that helped me `Agentic Coding`: concepts and hands-on Platform Engineering use cases `PostgreSQL`: From Metrics to Query Plan Analysis `VictoriaLogs`: What if logs management became simple and performant? `VictoriaMetrics` : Effective alerts, from theory to practice 🛠️ Harness the Power of `VictoriaMetrics` and `Grafana` Operators for Metrics Management `Dagger`: The missing piece of the developer experience? `TLS` with Gateway API: Efficient and Secure Management of Public and Private Certificates Going Further with `Crossplane`: Compositions and Functions Beyond Traditional VPNs: Simplifying Cloud Access with `Tailscale` `Gateway API`: Can I replace my Ingress Controller with `Cilium`? Applying GitOps Principles to Infrastructure: An overview of `tf-controller` `CloudNativePG`: An easy way to run PostgreSQL on Kubernetes 100% `GitOps` using Flux My Kubernetes cluster (GKE) with `Crossplane` Manage tools versions with `asdf` Helm workshop: Templating exercises Helm workshop: Build your first chart Helm workshop: Lifecycle operations Helm workshop: Ecosystem Helm workshop: Third party charts Helm workshop Kubernetes workshop: Manage permissions in Kubernetes Kubernetes workshop: Troubleshooting Kubernetes workshop: Resources allocation and autoscaling Kubernetes workshop: Local environment Run an application on Kubernetes Kubernetes workshop
Kubernetes workshop: Complete application stack
2021-05-05 · via Ogenki

ℹ️ This section is, for a most part, based on the official Kubernetes doc.

By the end of this lab we'll create the following components. You may want to come back to this schema from time to time in order to get the whole picture.

components

A database with a persistent volume

Check that your cluster is up and running and that your context is still configured with the namespace foo

1kubectl config get-contexts
2CURRENT   NAME           CLUSTER        AUTHINFO             NAMESPACE
3*         k3d-workshop   k3d-workshop   admin@k3d-workshop   foo

Create a persistent volume claim

There are several options when it comes to persistent workloads on Kubernetes. For this workshop we'll use our local disks thanks to the local path provisionner.

Create a persistentVolumeClaim, it will stay pending until a pod consumes it

1kubectl apply -f content/resources/kubernetes_workshop/mysql/pvc.yaml
2persistentvolumeclaim/local-path-mysql created
3
4kubectl get pvc
5NAME               STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
6local-path-mysql   Pending                                      local-path     16s

Create the MySQL secret

In Kubernetes sensitive data are stored in Secrets. Here we'll create a secret that stores the MySQL root password

1kubectl create secret generic mysql-pass --from-literal=password=YOUR_PASSWORD
2secret/mysql-pass created

Note that a secret is stored in an base64 encoded format and can be easily decoded. (There are best practices to enforce safe access to the secrets that we're not going to cover there)

 1kubectl get secrets mysql-pass -o yaml
 2apiVersion: v1
 3data:
 4  password: WU9VUl9QQVNTV09SRA==
 5kind: Secret
 6metadata:
 7  creationTimestamp: "2021-06-20T09:11:59Z"
 8  name: mysql-pass
 9  namespace: foo
10  resourceVersion: "2809"
11  uid: c96c58d6-8472-4d68-8554-5dcfb69d834c
12type: Opaque
13
14echo -n "WU9VUl9QQVNTV09SRA==" | base64 -d
15YOUR_PASSWORD

Run the MySQL deployment

We will now create a MySQL deployment. It will be composed of a single replica as we're accessing to a local volume and it is configured to make use of the secret we've created previously.

1kubectl apply -f content/resources/kubernetes_workshop/mysql/deployment.yaml
2deployment.apps/wordpress-mysql created
3
4kubectl get po -w
5NAME                               READY   STATUS              RESTARTS   AGE
6wordpress-mysql-6c597b98bd-vcm62   0/1     ContainerCreating   0          9s
7wordpress-mysql-6c597b98bd-vcm62   1/1     Running             0          13s
8^C

Service discovery in Kubernetes

In order to be able to call our MySQL deployment we may want to expose it using a service.

1kubectl apply -f content/resources/kubernetes_workshop/mysql/svc.yaml
2service/wordpress-mysql created
3
4kubectl get svc
5NAME              TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
6wordpress-mysql   ClusterIP   None         <none>        3306/TCP   6s

Kubernetes's service discovery is based on an internal DNS system. For instance a service A service is accessible using the following nomenclature: <service_name>.<Namespace>.svc.<Cluster_domain_name>

Let's try to access to the database server using a mysql client pod and create a database named foobar

 1kubectl run -ti --rm mysql-client --restart=Never --image=mysql:5.7 -- /bin/bash
 2If you don't see a command prompt, try pressing enter.
 3root@mysql-client:/# apt -qq update && apt install -yq netcat
 4...
 5Setting up netcat (1.10-41.1) ...
 6
 7
 8root@mysql-client:/# nc -vz wordpress-mysql.foo.svc.cluster.local 3306
 9DNS fwd/rev mismatch: wordpress-mysql.foo.svc.cluster.local != 10-42-1-8.wordpress-mysql.foo.svc.cluster.local
10wordpress-mysql.foo.svc.cluster.local [10.42.1.8] 3306 (?) open
11
12root@mysql-client:/# mysql -u root -h wordpress-mysql -p
13Enter password:
14...
15
16mysql> show databases;
17+--------------------+
18| Database           |
19+--------------------+
20| information_schema |
21| mysql              |
22| performance_schema |
23+--------------------+
243 rows in set (0.01 sec)
25
26mysql> create database foobar;
27Query OK, 1 row affected (0.00 sec)
28
29mysql> exit
30Bye

Note: You can either use the service name wordpress-mysql, or if your source pod is in another namespace use wordpress-mysql.foo

Check how the data is persisted with the local-path-provisioner

We may want to check how the data is stored. Now that we have a MySQL instance running and consuming the pvc, a persistent volume has been provision

1kubectl get pvc
2NAME               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
3local-path-mysql   Bound    pvc-4bb3c033-2261-4d5c-ba61-41e364769599   500Mi      RWO            local-path     14m

Having a closer look we notice that the volume is actually a directory within a worker node.

 1kubectl describe pv pvc-4bb3c033-2261-4d5c-ba61-41e364769599
 2Name:              pvc-4bb3c033-2261-4d5c-ba61-41e364769599
 3Labels:            <none>
 4Annotations:       pv.kubernetes.io/provisioned-by: rancher.io/local-path
 5Finalizers:        [kubernetes.io/pv-protection]
 6StorageClass:      local-path
 7Status:            Bound
 8Claim:             foo/local-path-mysql
 9Reclaim Policy:    Delete
10Access Modes:      RWO
11VolumeMode:        Filesystem
12Capacity:          500Mi
13Node Affinity:
14  Required Terms:
15    Term 0:        kubernetes.io/hostname in [k3d-workshop-agent-0]
16Message:
17Source:
18    Type:          HostPath (bare host directory volume)
19    Path:          /var/lib/rancher/k3s/storage/pvc-4bb3c033-2261-4d5c-ba61-41e364769599_foo_local-path-mysql
20    HostPathType:  DirectoryOrCreate
21Events:            <none>
1docker exec k3d-workshop-agent-0 ls /var/lib/rancher/k3s/storage/pvc-4bb3c033-2261-4d5c-ba61-41e364769599_foo_local-path-mysql
2auto.cnf
3foobar
4ib_logfile0
5ib_logfile1
6ibdata1
7mysql
8performance_schema

That means that even if you restart your laptop you should retrieve the data (here the database foobar we've created previously)

 1k3d cluster stop workshop
 2INFO[0000] Stopping cluster 'workshop'
 3
 4k3d cluster list
 5NAME       SERVERS   AGENTS   LOADBALANCER
 6workshop   0/1       0/1      true
 7
 8k3d cluster start workshop
 9INFO[0000] Starting cluster 'workshop'
10INFO[0000] Starting servers...
11INFO[0000] Starting Node 'k3d-workshop-server-0'
12INFO[0006] Starting agents...
13INFO[0006] Starting Node 'k3d-workshop-agent-0'
14INFO[0013] Starting helpers...
15INFO[0013] Starting Node 'k3d-workshop-serverlb'
16
17kubectl run -ti --rm mysql-client --restart=Never --image=mysql:5.7 -- mysql -u root -h wordpress-mysql --password="YOUR_PASSWORD"
18If you don't see a command prompt, try pressing enter.
19
20mysql> show databases;
21+--------------------+
22| Database           |
23+--------------------+
24| information_schema |
25| foobar             |
26| mysql              |
27| performance_schema |
28+--------------------+
294 rows in set (0.00 sec)

The Wordpress deployment

Now we will deploy the wordpress instance with a persistent volume.

So first of all create a pvc as follows

1kubectl apply -f content/resources/kubernetes_workshop/wordpress/pvc.yaml
2persistentvolumeclaim/wp-pv-claim created

Then create the deployment. Note that it is configured with our mysql database as backend.

1kubectl apply -f content/resources/kubernetes_workshop/wordpress/deployment.yaml
2deployment.apps/wordpress created
3
4$ kubectl get deploy
5NAME              READY   UP-TO-DATE   AVAILABLE   AGE
6wordpress-mysql   1/1     1            1           11h
7wordpress         1/1     1            1           4s

Most of the time, when we want to expose an HTTP service to the outside world (outside of the cluster), we would create an ingress

1kubectl apply -f content/resources/kubernetes_workshop/wordpress/svc.yaml
2service/wordpress created
3
4kubectl apply -f content/resources/kubernetes_workshop/wordpress/ingress.yaml
5ingress.networking.k8s.io/wordpress created

With k3d the ingress endpoint has been defined when we've created the cluster. With the parameter -p "8081:80@loadbalancer" Our wordpress should therefore be accessible through http://localhost:8081

wordpress

Configure your pods

A ConfigMap is a kubernetes resource that stores non-sensitive data. Its content can be consumed as config files, environment variables or command args.

Let's consider that we need a configfile to be mounted in our wordpress deployment as well as an environment variable made available.

Create a dumb "hello world" config file

1echo "Hello World!" > /tmp/helloworld.conf

Then we'll create a configmap that contains a file and environment variable we want to make use of. Note This following command doesn't actually apply the resource on our Kubernetes cluster. It just generate a local yaml file using --dry-run and -o yaml.

1kubectl create configmap helloworld --from-file=/tmp/helloworld.conf --from-literal=HELLO=WORLD -o yaml --dry-run=client > /tmp/cm.yaml

Check the configmap

1apiVersion: v1
2data:
3  HELLO: WORLD
4  helloworld.conf: |
5    Hello World!
6kind: ConfigMap
7metadata:
8  creationTimestamp: null
9  name: helloworld

And apply it

1$ kubectl apply -f /tmp/cm.yaml
2configmap/helloworld created

Now we're gonna make use of it by changing the wordpress deployment. For this kind of change it is recommended to use an IDE with a Kubernetes plugin that will highlight errors.

Edit the file located here: content/resources/kubernetes_workshop/wordpress/deployment.yaml

 1...
 2          env:
 3            - name: WORDPRESS_DB_HOST
 4              value: wordpress-mysql
 5            - name: WORDPRESS_DB_PASSWORD
 6              valueFrom:
 7                secretKeyRef:
 8                  name: mysql-pass
 9                  key: password
10            - name: HELLO
11              valueFrom:
12                configMapKeyRef:
13                  name: helloworld
14                  key: HELLO
15          volumeMounts:
16            - name: wordpress-persistent-storage
17              mountPath: /var/www/html
18            - name: helloworld-config
19              mountPath: /config
20      volumes:
21        - name: wordpress-persistent-storage
22          persistentVolumeClaim:
23            claimName: wp-pv-claim
24        - name: helloworld-config
25          configMap:
26            name: helloworld
27            items:
28              - key: helloworld.conf
29                path: helloworld.conf

Applying this change will trigger a rolling-update

1$ kubectl apply -f content/resources/kubernetes_workshop/wordpress/deployment.yaml
2deployment.apps/wordpress configured
3
4$ kubectl get po
5NAME                               READY   STATUS    RESTARTS   AGE
6wordpress-mysql-6c597b98bd-4mbbd   1/1     Running   2          41h
7wordpress-594f88c9c4-n9qqr         1/1     Running   0          5s

And the configuration will be available in the newly created pod

1$ kubectl exec -ti wordpress-594f88c9c4-n9qqr -- env | grep HELLO
2HELLO=WORLD
3
4$ kubectl exec -ti wordpress-594f88c9c4-n9qqr -- cat /config/helloworld.conf
5Hello World!

⚠️ Do not delete anything, we'll make use of these resources in the next section.

➡️ Next: Resources in Kubernetes