Project

General

Profile

The ungleich kubernetes infrastructure » History » Version 143

Nico Schottelius, 09/09/2022 08:36 PM

1 22 Nico Schottelius
h1. The ungleich kubernetes infrastructure and ungleich kubernetes manual
2 1 Nico Schottelius
3 3 Nico Schottelius
{{toc}}
4
5 1 Nico Schottelius
h2. Status
6
7 28 Nico Schottelius
This document is **pre-production**.
8
This document is to become the ungleich kubernetes infrastructure overview as well as the ungleich kubernetes manual.
9 1 Nico Schottelius
10 10 Nico Schottelius
h2. k8s clusters
11
12 123 Nico Schottelius
| Cluster            | Purpose/Setup     | Maintainer | Master(s)                     | argo                                                   | v4 http proxy | last verified |
13
| c0.k8s.ooo         | Dev               | -          | UNUSED                        |                                                        |               |    2021-10-05 |
14
| c1.k8s.ooo         | retired           |            | -                             |                                                        |               |    2022-03-15 |
15
| c2.k8s.ooo         | Dev p7 HW         | Nico       | server47 server53 server54    | "argo":https://argocd-server.argocd.svc.c2.k8s.ooo     |               |    2021-10-05 |
16
| c3.k8s.ooo         | retired           | -          | -                             |                                                        |               |    2021-10-05 |
17
| c4.k8s.ooo         | Dev2 p7 HW        | Jin-Guk    | server52 server53 server54    |                                                        |               |             - |
18
| c5.k8s.ooo         | retired           |            | -                             |                                                        |               |    2022-03-15 |
19
| c6.k8s.ooo         | Dev p6 VM Jin-Guk | Jin-Guk    |                               |                                                        |               |               |
20
| [[p5.k8s.ooo]]     | production        |            | server34 server36 server38    | "argo":https://argocd-server.argocd.svc.p5.k8s.ooo     | -             |               |
21
| [[p5-cow.k8s.ooo]] | production        | Nico       | server47 server51 server55    | "argo":https://argocd-server.argocd.svc.p5-cow.k8s.ooo |               |    2022-08-27 |
22
| [[p6.k8s.ooo]]     | production        |            | server67 server69 server71    | "argo":https://argocd-server.argocd.svc.p6.k8s.ooo     | 147.78.194.13 |    2021-10-05 |
23
| [[p10.k8s.ooo]]    | production        |            | server63 server65 server83    | "argo":https://argocd-server.argocd.svc.p10.k8s.ooo    | 147.78.194.12 |    2021-10-05 |
24
| [[k8s.ge.nau.so]]  | development       |            | server107 server108 server109 | "argo":https://argocd-server.argocd.svc.k8s.ge.nau.so  |               |               |
25
| [[dev.k8s.ooo]]    | development       |            | server110 server111 server112 | "argo":https://argocd-server.argocd.svc.dev.k8s.ooo    | -             |    2022-07-08 |
26 143 Nico Schottelius
| [[ge.nau.so]] | development | Nico | server107 server108 server109  | | | 2022-09-09 |
27 142 Nico Schottelius
| [[server121.k8s.ooo]] | production | Nico | server121 | | | 2022-09-06 |
28 21 Nico Schottelius
29 1 Nico Schottelius
h2. General architecture and components overview
30
31
* All k8s clusters are IPv6 only
32
* We use BGP peering to propagate podcidr and serviceCidr networks to our infrastructure
33
* The main public testing repository is "ungleich-k8s":https://code.ungleich.ch/ungleich-public/ungleich-k8s
34 18 Nico Schottelius
** Private configurations are found in the **k8s-config** repository
35 1 Nico Schottelius
36
h3. Cluster types
37
38 28 Nico Schottelius
| **Type/Feature**            | **Development**                | **Production**         |
39
| Min No. nodes               | 3 (1 master, 3 worker)         | 5 (3 master, 3 worker) |
40
| Recommended minimum         | 4 (dedicated master, 3 worker) | 8 (3 master, 5 worker) |
41
| Separation of control plane | optional                       | recommended            |
42
| Persistent storage          | required                       | required               |
43
| Number of storage monitors  | 3                              | 5                      |
44 1 Nico Schottelius
45 43 Nico Schottelius
h2. General k8s operations
46 1 Nico Schottelius
47 46 Nico Schottelius
h3. Cheat sheet / external great references
48
49
* "kubectl cheatsheet":https://kubernetes.io/docs/reference/kubectl/cheatsheet/
50
51 117 Nico Schottelius
h3. Allowing to schedule work on the control plane / removing node taints
52 69 Nico Schottelius
53
* Mostly for single node / test / development clusters
54
* Just remove the master taint as follows
55
56
<pre>
57
kubectl taint nodes --all node-role.kubernetes.io/master-
58 118 Nico Schottelius
kubectl taint nodes --all node-role.kubernetes.io/control-plane-
59 69 Nico Schottelius
</pre>
60 1 Nico Schottelius
61 117 Nico Schottelius
You can check the node taints using @kubectl describe node ...@
62 69 Nico Schottelius
63 44 Nico Schottelius
h3. Get the cluster admin.conf
64
65
* On the masters of each cluster you can find the file @/etc/kubernetes/admin.conf@
66
* To be able to administrate the cluster you can copy the admin.conf to your local machine
67
* Multi cluster debugging can very easy if you name the config ~/cX-admin.conf (see example below)
68
69
<pre>
70
% scp root@server47.place7.ungleich.ch:/etc/kubernetes/admin.conf ~/c2-admin.conf
71
% export KUBECONFIG=~/c2-admin.conf    
72
% kubectl get nodes
73
NAME       STATUS                     ROLES                  AGE   VERSION
74
server47   Ready                      control-plane,master   82d   v1.22.0
75
server48   Ready                      control-plane,master   82d   v1.22.0
76
server49   Ready                      <none>                 82d   v1.22.0
77
server50   Ready                      <none>                 82d   v1.22.0
78
server59   Ready                      control-plane,master   82d   v1.22.0
79
server60   Ready,SchedulingDisabled   <none>                 82d   v1.22.0
80
server61   Ready                      <none>                 82d   v1.22.0
81
server62   Ready                      <none>                 82d   v1.22.0               
82
</pre>
83
84 18 Nico Schottelius
h3. Installing a new k8s cluster
85 8 Nico Schottelius
86 9 Nico Schottelius
* Decide on the cluster name (usually *cX.k8s.ooo*), X counting upwards
87 28 Nico Schottelius
** Using pXX.k8s.ooo for production clusters of placeXX
88 9 Nico Schottelius
* Use cdist to configure the nodes with requirements like crio
89
* Decide between single or multi node control plane setups (see below)
90 28 Nico Schottelius
** Single control plane suitable for development clusters
91 9 Nico Schottelius
92 28 Nico Schottelius
Typical init procedure:
93 9 Nico Schottelius
94 28 Nico Schottelius
* Single control plane: @kubeadm init --config bootstrap/XXX/kubeadm.yaml@
95
* Multi control plane (HA): @kubeadm init --config bootstrap/XXX/kubeadm.yaml --upload-certs@
96 10 Nico Schottelius
97 29 Nico Schottelius
h3. Deleting a pod that is hanging in terminating state
98
99
<pre>
100
kubectl delete pod <PODNAME> --grace-period=0 --force --namespace <NAMESPACE>
101
</pre>
102
103
(from https://stackoverflow.com/questions/35453792/pods-stuck-in-terminating-status)
104
105 42 Nico Schottelius
h3. Listing nodes of a cluster
106
107
<pre>
108
[15:05] bridge:~% kubectl get nodes
109
NAME       STATUS   ROLES                  AGE   VERSION
110
server22   Ready    <none>                 52d   v1.22.0
111
server23   Ready    <none>                 52d   v1.22.2
112
server24   Ready    <none>                 52d   v1.22.0
113
server25   Ready    <none>                 52d   v1.22.0
114
server26   Ready    <none>                 52d   v1.22.0
115
server27   Ready    <none>                 52d   v1.22.0
116
server63   Ready    control-plane,master   52d   v1.22.0
117
server64   Ready    <none>                 52d   v1.22.0
118
server65   Ready    control-plane,master   52d   v1.22.0
119
server66   Ready    <none>                 52d   v1.22.0
120
server83   Ready    control-plane,master   52d   v1.22.0
121
server84   Ready    <none>                 52d   v1.22.0
122
server85   Ready    <none>                 52d   v1.22.0
123
server86   Ready    <none>                 52d   v1.22.0
124
</pre>
125
126 41 Nico Schottelius
h3. Removing / draining a node
127
128
Usually @kubectl drain server@ should do the job, but sometimes we need to be more aggressive:
129
130 1 Nico Schottelius
<pre>
131 103 Nico Schottelius
kubectl drain --delete-emptydir-data --ignore-daemonsets serverXX
132 42 Nico Schottelius
</pre>
133
134
h3. Readding a node after draining
135
136
<pre>
137
kubectl uncordon serverXX
138 1 Nico Schottelius
</pre>
139 43 Nico Schottelius
140 50 Nico Schottelius
h3. (Re-)joining worker nodes after creating the cluster
141 49 Nico Schottelius
142
* We need to have an up-to-date token
143
* We use different join commands for the workers and control plane nodes
144
145
Generating the join command on an existing control plane node:
146
147
<pre>
148
kubeadm token create --print-join-command
149
</pre>
150
151 50 Nico Schottelius
h3. (Re-)joining control plane nodes after creating the cluster
152 1 Nico Schottelius
153 50 Nico Schottelius
* We generate the token again
154
* We upload the certificates
155
* We need to combine/create the join command for the control plane node
156
157
Example session:
158
159
<pre>
160
% kubeadm token create --print-join-command
161
kubeadm join p10-api.k8s.ooo:6443 --token xmff4i.ABC --discovery-token-ca-cert-hash sha256:longhash 
162
163
% kubeadm init phase upload-certs --upload-certs
164
[upload-certs] Storing the certificates in Secret "kubeadm-certs" in the "kube-system" Namespace
165
[upload-certs] Using certificate key:
166
CERTKEY
167
168
# Then we use these two outputs on the joining node:
169
170
kubeadm join p10-api.k8s.ooo:6443 --token xmff4i.ABC --discovery-token-ca-cert-hash sha256:longhash --control-plane --certificate-key CERTKEY
171
</pre>
172
173
Commands to be used on a control plane node:
174
175
<pre>
176
kubeadm token create --print-join-command
177
kubeadm init phase upload-certs --upload-certs
178
</pre>
179
180
Commands to be used on the joining node:
181
182
<pre>
183
JOINCOMMAND --control-plane --certificate-key CERTKEY
184
</pre>
185 49 Nico Schottelius
186 51 Nico Schottelius
SEE ALSO
187
188
* https://stackoverflow.com/questions/63936268/how-to-generate-kubeadm-token-for-secondary-control-plane-nodes
189
* https://blog.scottlowe.org/2019/08/15/reconstructing-the-join-command-for-kubeadm/
190
191 53 Nico Schottelius
h3. How to fix etcd does not start when rejoining a kubernetes cluster as a control plane
192 52 Nico Schottelius
193
If during the above step etcd does not come up, @kubeadm join@ can hang as follows:
194
195
<pre>
196
[control-plane] Creating static Pod manifest for "kube-apiserver"                                                              
197
[control-plane] Creating static Pod manifest for "kube-controller-manager"                                                     
198
[control-plane] Creating static Pod manifest for "kube-scheduler"                                                              
199
[check-etcd] Checking that the etcd cluster is healthy                                                                         
200
error execution phase check-etcd: etcd cluster is not healthy: failed to dial endpoint https://[2a0a:e5c0:10:1:225:b3ff:fe20:37
201
8a]:2379 with maintenance client: context deadline exceeded                                                                    
202
To see the stack trace of this error execute with --v=5 or higher         
203
</pre>
204
205
Then the problem is likely that the etcd server is still a member of the cluster. We first need to remove it from the etcd cluster and then the join works.
206
207
To fix this we do:
208
209
* Find a working etcd pod
210
* Find the etcd members / member list
211
* Remove the etcd member that we want to re-join the cluster
212
213
214
<pre>
215
# Find the etcd pods
216
kubectl -n kube-system get pods -l component=etcd,tier=control-plane
217
218
# Get the list of etcd servers with the member id 
219
kubectl exec -n kube-system -ti ETCDPODNAME -- etcdctl --endpoints '[::1]:2379' --cacert /etc/kubernetes/pki/etcd/ca.crt --cert  /etc/kubernetes/pki/etcd/server.crt --key /etc/kubernetes/pki/etcd/server.key member list
220
221
# Remove the member
222
kubectl exec -n kube-system -ti ETCDPODNAME -- etcdctl --endpoints '[::1]:2379' --cacert /etc/kubernetes/pki/etcd/ca.crt --cert  /etc/kubernetes/pki/etcd/server.crt --key /etc/kubernetes/pki/etcd/server.key member remove MEMBERID
223
</pre>
224
225
Sample session:
226
227
<pre>
228
[10:48] line:~% kubectl -n kube-system get pods -l component=etcd,tier=control-plane
229
NAME            READY   STATUS    RESTARTS     AGE
230
etcd-server63   1/1     Running   0            3m11s
231
etcd-server65   1/1     Running   3            7d2h
232
etcd-server83   1/1     Running   8 (6d ago)   7d2h
233
[10:48] line:~% kubectl exec -n kube-system -ti etcd-server65 -- etcdctl --endpoints '[::1]:2379' --cacert /etc/kubernetes/pki/etcd/ca.crt --cert  /etc/kubernetes/pki/etcd/server.crt --key /etc/kubernetes/pki/etcd/server.key member list
234
356891cd676df6e4, started, server65, https://[2a0a:e5c0:10:1:225:b3ff:fe20:375c]:2380, https://[2a0a:e5c0:10:1:225:b3ff:fe20:375c]:2379, false
235
371b8a07185dee7e, started, server63, https://[2a0a:e5c0:10:1:225:b3ff:fe20:378a]:2380, https://[2a0a:e5c0:10:1:225:b3ff:fe20:378a]:2379, false
236
5942bc58307f8af9, started, server83, https://[2a0a:e5c0:10:1:3e4a:92ff:fe79:bb98]:2380, https://[2a0a:e5c0:10:1:3e4a:92ff:fe79:bb98]:2379, false
237
238
[10:48] line:~% kubectl exec -n kube-system -ti etcd-server65 -- etcdctl --endpoints '[::1]:2379' --cacert /etc/kubernetes/pki/etcd/ca.crt --cert  /etc/kubernetes/pki/etcd/server.crt --key /etc/kubernetes/pki/etcd/server.key member remove 371b8a07185dee7e
239
Member 371b8a07185dee7e removed from cluster e3c0805f592a8f77
240 1 Nico Schottelius
241
</pre>
242
243
SEE ALSO
244
245
* We found the solution using https://stackoverflow.com/questions/67921552/re-installed-node-cannot-join-kubernetes-cluster
246 56 Nico Schottelius
247 101 Nico Schottelius
h3. Hardware Maintenance using ungleich-hardware
248
249
Use the following manifest and replace the HOST with the actual host:
250
251
<pre>
252
apiVersion: v1
253
kind: Pod
254
metadata:
255
  name: ungleich-hardware-HOST
256
spec:
257
  containers:
258
  - name: ungleich-hardware
259
    image: ungleich/ungleich-hardware:0.0.5
260
    args:
261
    - sleep
262
    - "1000000"
263
    volumeMounts:
264
      - mountPath: /dev
265
        name: dev
266
    securityContext:
267
      privileged: true
268
  nodeSelector:
269
    kubernetes.io/hostname: "HOST"
270
271
  volumes:
272
    - name: dev
273
      hostPath:
274
        path: /dev
275
</pre>
276
277 102 Nico Schottelius
Also see: [[The_ungleich_hardware_maintenance_guide]]
278
279 105 Nico Schottelius
h3. Triggering a cronjob / creating a job from a cronjob
280 104 Nico Schottelius
281
To test a cronjob, we can create a job from a cronjob:
282
283
<pre>
284
kubectl create job --from=cronjob/volume2-daily-backup volume2-manual
285
</pre>
286
287
This creates a job volume2-manual based on the cronjob  volume2-daily
288
289 112 Nico Schottelius
h3. su-ing into a user that has nologin shell set
290
291
Many times users are having nologin as their shell inside the container. To be able to execute maintenance commands within the
292
container, we can use @su -s /bin/sh@ like this:
293
294
<pre>
295
su -s /bin/sh -c '/path/to/your/script' testuser
296
</pre>
297
298
Found on https://serverfault.com/questions/351046/how-to-run-command-as-user-who-has-usr-sbin-nologin-as-shell
299
300 113 Nico Schottelius
h3. How to print a secret value
301
302
Assuming you want the "password" item from a secret, use:
303
304
<pre>
305
kubectl get secret SECRETNAME -o jsonpath="{.data.password}" | base64 -d; echo "" 
306
</pre>
307
308 62 Nico Schottelius
h2. Calico CNI
309
310
h3. Calico Installation
311
312
* We install "calico using helm":https://docs.projectcalico.org/getting-started/kubernetes/helm
313
* This has the following advantages:
314
** Easy to upgrade
315
** Does not require os to configure IPv6/dual stack settings as the tigera operator figures out things on its own
316
317
Usually plain calico can be installed directly using:
318
319
<pre>
320 125 Nico Schottelius
VERSION=v3.23.3
321 120 Nico Schottelius
helm repo add projectcalico https://docs.projectcalico.org/charts
322 124 Nico Schottelius
helm upgrade --install --namespace tigera calico projectcalico/tigera-operator --version $VERSION --create-namespace
323 1 Nico Schottelius
</pre>
324 92 Nico Schottelius
325
* Check the tags on https://github.com/projectcalico/calico/tags for the latest release
326 62 Nico Schottelius
327
h3. Installing calicoctl
328
329 115 Nico Schottelius
* General installation instructions, including binary download: https://projectcalico.docs.tigera.io/maintenance/clis/calicoctl/install
330
331 62 Nico Schottelius
To be able to manage and configure calico, we need to 
332
"install calicoctl (we choose the version as a pod)":https://docs.projectcalico.org/getting-started/clis/calicoctl/install#install-calicoctl-as-a-kubernetes-pod
333
334
<pre>
335
kubectl apply -f https://docs.projectcalico.org/manifests/calicoctl.yaml
336
</pre>
337
338 93 Nico Schottelius
Or version specific:
339
340
<pre>
341
kubectl apply -f https://github.com/projectcalico/calico/blob/v3.20.4/manifests/calicoctl.yaml
342 97 Nico Schottelius
343
# For 3.22
344
kubectl apply -f https://projectcalico.docs.tigera.io/archive/v3.22/manifests/calicoctl.yaml
345 93 Nico Schottelius
</pre>
346
347 70 Nico Schottelius
And making it easier accessible by alias:
348
349
<pre>
350
alias calicoctl="kubectl exec -i -n kube-system calicoctl -- /calicoctl"
351
</pre>
352
353 62 Nico Schottelius
h3. Calico configuration
354
355 63 Nico Schottelius
By default our k8s clusters "BGP peer":https://docs.projectcalico.org/networking/bgp
356
with an upstream router to propagate podcidr and servicecidr.
357 62 Nico Schottelius
358
Default settings in our infrastructure:
359
360
* We use a full-mesh using the @nodeToNodeMeshEnabled: true@ option
361
* We keep the original next hop so that *only* the server with the pod is announcing it (instead of ecmp)
362 1 Nico Schottelius
* We use private ASNs for k8s clusters
363 63 Nico Schottelius
* We do *not* use any overlay
364 62 Nico Schottelius
365
After installing calico and calicoctl the last step of the installation is usually:
366
367 1 Nico Schottelius
<pre>
368 79 Nico Schottelius
calicoctl create -f - < calico-bgp.yaml
369 62 Nico Schottelius
</pre>
370
371
372
A sample BGP configuration:
373
374
<pre>
375
---
376
apiVersion: projectcalico.org/v3
377
kind: BGPConfiguration
378
metadata:
379
  name: default
380
spec:
381
  logSeverityScreen: Info
382
  nodeToNodeMeshEnabled: true
383
  asNumber: 65534
384
  serviceClusterIPs:
385
  - cidr: 2a0a:e5c0:10:3::/108
386
  serviceExternalIPs:
387
  - cidr: 2a0a:e5c0:10:3::/108
388
---
389
apiVersion: projectcalico.org/v3
390
kind: BGPPeer
391
metadata:
392
  name: router1-place10
393
spec:
394
  peerIP: 2a0a:e5c0:10:1::50
395
  asNumber: 213081
396
  keepOriginalNextHop: true
397
</pre>
398
399 126 Nico Schottelius
h2. Cilium CNI (experimental)
400
401 137 Nico Schottelius
h3. Status
402
403 138 Nico Schottelius
*NO WORKING CILIUM CONFIGURATION FOR IPV6 only modes*
404 137 Nico Schottelius
405 128 Nico Schottelius
h3. BGP configuration
406
407
* The cilium-operator will not start without a correct configmap being present beforehand (see error message below)
408
* Creating the bgp config beforehand as a configmap is thus required.
409
410
The error one gets without the configmap present:
411
412
Pods are hanging with:
413
414
<pre>
415
cilium-bpqm6                       0/1     Init:0/4            0             9s
416
cilium-operator-5947d94f7f-5bmh2   0/1     ContainerCreating   0             9s
417
</pre>
418
419
The error message in the cilium-*perator is:
420
421
<pre>
422
Events:
423
  Type     Reason       Age                From               Message
424
  ----     ------       ----               ----               -------
425
  Normal   Scheduled    80s                default-scheduler  Successfully assigned kube-system/cilium-operator-5947d94f7f-lqcsp to server56
426
  Warning  FailedMount  16s (x8 over 80s)  kubelet            MountVolume.SetUp failed for volume "bgp-config-path" : configmap "bgp-config" not found
427
</pre>
428
429
A correct bgp config looks like this:
430
431
<pre>
432
apiVersion: v1
433
kind: ConfigMap
434
metadata:
435
  name: bgp-config
436
  namespace: kube-system
437
data:
438
  config.yaml: |
439
    peers:
440
      - peer-address: 2a0a:e5c0::46
441
        peer-asn: 209898
442
        my-asn: 65533
443
      - peer-address: 2a0a:e5c0::47
444
        peer-asn: 209898
445
        my-asn: 65533
446
    address-pools:
447
      - name: default
448
        protocol: bgp
449
        addresses:
450
          - 2a0a:e5c0:0:14::/64
451
</pre>
452
453 127 Nico Schottelius
h3. Installation
454
455 130 Nico Schottelius
Adding the repo
456 127 Nico Schottelius
<pre>
457 1 Nico Schottelius
458 127 Nico Schottelius
helm repo add cilium https://helm.cilium.io/
459 129 Nico Schottelius
helm repo update
460 130 Nico Schottelius
</pre>
461 1 Nico Schottelius
462 130 Nico Schottelius
Installing + configuring cilium
463
<pre>
464 129 Nico Schottelius
version=1.12.1
465 135 Nico Schottelius
ipv6pool=2a0a:e5c0:0:14::/112
466 129 Nico Schottelius
467 130 Nico Schottelius
468 1 Nico Schottelius
helm upgrade --install cilium cilium/cilium --version $version \
469 129 Nico Schottelius
  --namespace kube-system \
470
  --set ipv4.enabled=false \
471 1 Nico Schottelius
  --set ipv6.enabled=true \
472 131 Nico Schottelius
  --set ipam.operator.clusterPoolIPv6PodCIDRList=$ipv6pool \
473 1 Nico Schottelius
  --set bgpControlPlane.enabled=true
474 136 Nico Schottelius
475
#   --set bgp.enabled=true --set bgp.announce.podCIDR=true \
476 127 Nico Schottelius
477
# Show possible configuration options
478
helm show values cilium/cilium
479
480 1 Nico Schottelius
</pre>
481 132 Nico Schottelius
482
Using a /64 for ipam.operator.clusterPoolIPv6PodCIDRList fails with:
483
484
<pre>
485
level=fatal msg="Unable to init cluster-pool allocator" error="unable to initialize IPv6 allocator New CIDR set failed; the node CIDR size is too big" subsys=cilium-operator-generic
486
</pre>
487
488 126 Nico Schottelius
489 1 Nico Schottelius
See also https://github.com/cilium/cilium/issues/20756
490 135 Nico Schottelius
491
Seems a /112 is actually working.
492
493
h3. Kernel modules
494
495
Cilium requires the following modules to be loaded on the host (not loaded by default):
496
497
<pre>
498
modprobe  ip6table_raw
499
modprobe  ip6table_filter
500
</pre>
501 133 Nico Schottelius
502 122 Nico Schottelius
h2. ArgoCD 
503 56 Nico Schottelius
504 60 Nico Schottelius
h3. Argocd Installation
505 1 Nico Schottelius
506 116 Nico Schottelius
* See https://argo-cd.readthedocs.io/en/stable/
507
508 60 Nico Schottelius
As there is no configuration management present yet, argocd is installed using
509
510 1 Nico Schottelius
<pre>
511 60 Nico Schottelius
kubectl create namespace argocd
512 86 Nico Schottelius
513 96 Nico Schottelius
# Specific Version
514
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v2.3.2/manifests/install.yaml
515 86 Nico Schottelius
516
# OR: latest stable
517 60 Nico Schottelius
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
518 56 Nico Schottelius
</pre>
519 1 Nico Schottelius
520 116 Nico Schottelius
521 1 Nico Schottelius
522 60 Nico Schottelius
h3. Get the argocd credentials
523
524
<pre>
525
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d; echo ""
526
</pre>
527 52 Nico Schottelius
528 87 Nico Schottelius
h3. Accessing argocd
529
530
In regular IPv6 clusters:
531
532
* Navigate to https://argocd-server.argocd.CLUSTERDOMAIN
533
534
In legacy IPv4 clusters
535
536
<pre>
537
kubectl --namespace argocd port-forward svc/argocd-server 8080:80
538
</pre>
539
540 88 Nico Schottelius
* Navigate to https://localhost:8080
541
542 68 Nico Schottelius
h3. Using the argocd webhook to trigger changes
543 67 Nico Schottelius
544
* To trigger changes post json https://argocd.example.com/api/webhook
545
546 72 Nico Schottelius
h3. Deploying an application
547
548
* Applications are deployed via git towards gitea (code.ungleich.ch) and then pulled by argo
549 73 Nico Schottelius
* Always include the *redmine-url* pointing to the (customer) ticket
550
** Also add the support-url if it exists
551 72 Nico Schottelius
552
Application sample
553
554
<pre>
555
apiVersion: argoproj.io/v1alpha1
556
kind: Application
557
metadata:
558
  name: gitea-CUSTOMER
559
  namespace: argocd
560
spec:
561
  destination:
562
    namespace: default
563
    server: 'https://kubernetes.default.svc'
564
  source:
565
    path: apps/prod/gitea
566
    repoURL: 'https://code.ungleich.ch/ungleich-intern/k8s-config.git'
567
    targetRevision: HEAD
568
    helm:
569
      parameters:
570
        - name: storage.data.storageClass
571
          value: rook-ceph-block-hdd
572
        - name: storage.data.size
573
          value: 200Gi
574
        - name: storage.db.storageClass
575
          value: rook-ceph-block-ssd
576
        - name: storage.db.size
577
          value: 10Gi
578
        - name: storage.letsencrypt.storageClass
579
          value: rook-ceph-block-hdd
580
        - name: storage.letsencrypt.size
581
          value: 50Mi
582
        - name: letsencryptStaging
583
          value: 'no'
584
        - name: fqdn
585
          value: 'code.verua.online'
586
  project: default
587
  syncPolicy:
588
    automated:
589
      prune: true
590
      selfHeal: true
591
  info:
592
    - name: 'redmine-url'
593
      value: 'https://redmine.ungleich.ch/issues/ISSUEID'
594
    - name: 'support-url'
595
      value: 'https://support.ungleich.ch/Ticket/Display.html?id=TICKETID'
596
</pre>
597
598 80 Nico Schottelius
h2. Helm related operations and conventions
599 55 Nico Schottelius
600 61 Nico Schottelius
We use helm charts extensively.
601
602
* In production, they are managed via argocd
603
* In development, helm chart can de developed and deployed manually using the helm utility.
604
605 55 Nico Schottelius
h3. Installing a helm chart
606
607
One can use the usual pattern of
608
609
<pre>
610
helm install <releasename> <chartdirectory>
611
</pre>
612
613
However often you want to reinstall/update when testing helm charts. The following pattern is "better", because it allows you to reinstall, if it is already installed:
614
615
<pre>
616
helm upgrade --install <releasename> <chartdirectory>
617 1 Nico Schottelius
</pre>
618 80 Nico Schottelius
619
h3. Naming services and deployments in helm charts [Application labels]
620
621
* We always have {{ .Release.Name }} to identify the current "instance"
622
* Deployments:
623
** use @app: <what it is>@, f.i. @app: nginx@, @app: postgres@, ...
624 81 Nico Schottelius
* See more about standard labels on
625
** https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/
626
** https://helm.sh/docs/chart_best_practices/labels/
627 55 Nico Schottelius
628 139 Nico Schottelius
h2. Rook + Ceph
629
630
h3. Installation
631
632
* Usually directly via argocd
633
634
Manual steps:
635
636
<pre>
637
638
</pre>
639 43 Nico Schottelius
640 71 Nico Schottelius
h3. Executing ceph commands
641
642
Using the ceph-tools pod as follows:
643
644
<pre>
645
kubectl exec -n rook-ceph -ti $(kubectl -n rook-ceph get pods -l app=rook-ceph-tools -o jsonpath='{.items[*].metadata.name}') -- ceph -s
646
</pre>
647
648 43 Nico Schottelius
h3. Inspecting the logs of a specific server
649
650
<pre>
651
# Get the related pods
652
kubectl -n rook-ceph get pods -l app=rook-ceph-osd-prepare 
653
...
654
655
# Inspect the logs of a specific pod
656
kubectl -n rook-ceph logs -f rook-ceph-osd-prepare-server23--1-444qx
657
658 71 Nico Schottelius
</pre>
659
660
h3. Inspecting the logs of the rook-ceph-operator
661
662
<pre>
663
kubectl -n rook-ceph logs -f -l app=rook-ceph-operator
664 43 Nico Schottelius
</pre>
665
666 121 Nico Schottelius
h3. Restarting the rook operator
667
668
<pre>
669
kubectl -n rook-ceph delete pods  -l app=rook-ceph-operator
670
</pre>
671
672 43 Nico Schottelius
h3. Triggering server prepare / adding new osds
673
674
The rook-ceph-operator triggers/watches/creates pods to maintain hosts. To trigger a full "re scan", simply delete that pod:
675
676
<pre>
677
kubectl -n rook-ceph delete pods -l app=rook-ceph-operator
678
</pre>
679
680
This will cause all the @rook-ceph-osd-prepare-..@ jobs to be recreated and thus OSDs to be created, if new disks have been added.
681
682
h3. Removing an OSD
683
684
* See "Ceph OSD Management":https://rook.io/docs/rook/v1.7/ceph-osd-mgmt.html
685 77 Nico Schottelius
* More specifically: https://github.com/rook/rook/blob/release-1.7/cluster/examples/kubernetes/ceph/osd-purge.yaml
686 99 Nico Schottelius
* Then delete the related deployment
687 41 Nico Schottelius
688 98 Nico Schottelius
Set osd id in the osd-purge.yaml and apply it. OSD should be down before.
689
690
<pre>
691
apiVersion: batch/v1
692
kind: Job
693
metadata:
694
  name: rook-ceph-purge-osd
695
  namespace: rook-ceph # namespace:cluster
696
  labels:
697
    app: rook-ceph-purge-osd
698
spec:
699
  template:
700
    metadata:
701
      labels:
702
        app: rook-ceph-purge-osd
703
    spec:
704
      serviceAccountName: rook-ceph-purge-osd
705
      containers:
706
        - name: osd-removal
707
          image: rook/ceph:master
708
          # TODO: Insert the OSD ID in the last parameter that is to be removed
709
          # The OSD IDs are a comma-separated list. For example: "0" or "0,2".
710
          # If you want to preserve the OSD PVCs, set `--preserve-pvc true`.
711
          #
712
          # A --force-osd-removal option is available if the OSD should be destroyed even though the
713
          # removal could lead to data loss.
714
          args:
715
            - "ceph"
716
            - "osd"
717
            - "remove"
718
            - "--preserve-pvc"
719
            - "false"
720
            - "--force-osd-removal"
721
            - "false"
722
            - "--osd-ids"
723
            - "SETTHEOSDIDHERE"
724
          env:
725
            - name: POD_NAMESPACE
726
              valueFrom:
727
                fieldRef:
728
                  fieldPath: metadata.namespace
729
            - name: ROOK_MON_ENDPOINTS
730
              valueFrom:
731
                configMapKeyRef:
732
                  key: data
733
                  name: rook-ceph-mon-endpoints
734
            - name: ROOK_CEPH_USERNAME
735
              valueFrom:
736
                secretKeyRef:
737
                  key: ceph-username
738
                  name: rook-ceph-mon
739
            - name: ROOK_CEPH_SECRET
740
              valueFrom:
741
                secretKeyRef:
742
                  key: ceph-secret
743
                  name: rook-ceph-mon
744
            - name: ROOK_CONFIG_DIR
745
              value: /var/lib/rook
746
            - name: ROOK_CEPH_CONFIG_OVERRIDE
747
              value: /etc/rook/config/override.conf
748
            - name: ROOK_FSID
749
              valueFrom:
750
                secretKeyRef:
751
                  key: fsid
752
                  name: rook-ceph-mon
753
            - name: ROOK_LOG_LEVEL
754
              value: DEBUG
755
          volumeMounts:
756
            - mountPath: /etc/ceph
757
              name: ceph-conf-emptydir
758
            - mountPath: /var/lib/rook
759
              name: rook-config
760
      volumes:
761
        - emptyDir: {}
762
          name: ceph-conf-emptydir
763
        - emptyDir: {}
764
          name: rook-config
765
      restartPolicy: Never
766
767
768 99 Nico Schottelius
</pre>
769
770
Deleting the deployment:
771
772
<pre>
773
[18:05] bridge:~% kubectl -n rook-ceph delete deployment rook-ceph-osd-6
774
deployment.apps "rook-ceph-osd-6" deleted
775 98 Nico Schottelius
</pre>
776
777 76 Nico Schottelius
h2. Harbor
778
779
* We user "Harbor":https://goharbor.io/ for caching and as an image registry. Internal app reference: apps/prod/harbor.
780
* The admin password is in the password store, auto generated per cluster
781
* At the moment harbor only authenticates against the internal ldap tree
782
783
h3. LDAP configuration
784
785
* The url needs to be ldaps://...
786
* uid = uid
787
* rest standard
788 75 Nico Schottelius
789 89 Nico Schottelius
h2. Monitoring / Prometheus
790
791 90 Nico Schottelius
* Via "kube-prometheus":https://github.com/prometheus-operator/kube-prometheus/
792 89 Nico Schottelius
793 91 Nico Schottelius
Access via ...
794
795
* http://prometheus-k8s.monitoring.svc:9090
796
* http://grafana.monitoring.svc:3000
797
* http://alertmanager.monitoring.svc:9093
798
799
800 100 Nico Schottelius
h3. Prometheus Options
801
802
* "helm/kube-prometheus-stack":https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack
803
** Includes dashboards and co.
804
* "manifest based kube-prometheus":https://github.com/prometheus-operator/kube-prometheus
805
** Includes dashboards and co.
806
* "Prometheus Operator (mainly CRD manifest":https://github.com/prometheus-operator/prometheus-operator
807
808 91 Nico Schottelius
809 82 Nico Schottelius
h2. Nextcloud
810
811 85 Nico Schottelius
h3. How to get the nextcloud credentials 
812 84 Nico Schottelius
813
* The initial username is set to "nextcloud"
814
* The password is autogenerated and saved in a kubernetes secret
815
816
<pre>
817 85 Nico Schottelius
kubectl get secret RELEASENAME-nextcloud -o jsonpath="{.data.PASSWORD}" | base64 -d; echo "" 
818 84 Nico Schottelius
</pre>
819
820 83 Nico Schottelius
h3. How to fix "Access through untrusted domain"
821
822 82 Nico Schottelius
* Nextcloud stores the initial domain configuration
823 1 Nico Schottelius
* If the FQDN is changed, it will show the error message "Access through untrusted domain"
824 82 Nico Schottelius
* To fix, edit /var/www/html/config/config.php and correct the domain
825 83 Nico Schottelius
* Then delete the pods
826 82 Nico Schottelius
827 1 Nico Schottelius
h2. Infrastructure versions
828 35 Nico Schottelius
829 57 Nico Schottelius
h3. ungleich kubernetes infrastructure v5 (2021-10)
830 1 Nico Schottelius
831 57 Nico Schottelius
Clusters are configured / setup in this order:
832
833
* Bootstrap via kubeadm
834 59 Nico Schottelius
* "Networking via calico + BGP (non ECMP) using helm":https://docs.projectcalico.org/getting-started/kubernetes/helm
835
* "ArgoCD for CD":https://argo-cd.readthedocs.io/en/stable/
836
** "rook for storage via argocd":https://rook.io/
837 58 Nico Schottelius
** haproxy for in IPv6-cluster-IPv4-to-IPv6 proxy via argocd
838
** "kubernetes-secret-generator for in cluster secrets":https://github.com/mittwald/kubernetes-secret-generator
839
** "ungleich-certbot managing certs and nginx":https://hub.docker.com/repository/docker/ungleich/ungleich-certbot
840
841 57 Nico Schottelius
842
h3. ungleich kubernetes infrastructure v4 (2021-09)
843
844 54 Nico Schottelius
* rook is configured via manifests instead of using the rook-ceph-cluster helm chart
845 1 Nico Schottelius
* The rook operator is still being installed via helm
846 35 Nico Schottelius
847 57 Nico Schottelius
h3. ungleich kubernetes infrastructure v3 (2021-07)
848 1 Nico Schottelius
849 10 Nico Schottelius
* rook is now installed via helm via argocd instead of directly via manifests
850 28 Nico Schottelius
851 57 Nico Schottelius
h3. ungleich kubernetes infrastructure v2 (2021-05)
852 28 Nico Schottelius
853
* Replaced fluxv2 from ungleich k8s v1 with argocd
854 1 Nico Schottelius
** argocd can apply helm templates directly without needing to go through Chart releases
855 28 Nico Schottelius
* We are also using argoflow for build flows
856
* Planned to add "kaniko":https://github.com/GoogleContainerTools/kaniko for image building
857
858 57 Nico Schottelius
h3. ungleich kubernetes infrastructure v1 (2021-01)
859 28 Nico Schottelius
860
We are using the following components:
861
862
* "Calico as a CNI":https://www.projectcalico.org/ with BGP, IPv6 only, no encapsulation
863
** Needed for basic networking
864
* "kubernetes-secret-generator":https://github.com/mittwald/kubernetes-secret-generator for creating secrets
865
** Needed so that secrets are not stored in the git repository, but only in the cluster
866
* "ungleich-certbot":https://hub.docker.com/repository/docker/ungleich/ungleich-certbot
867
** Needed to get letsencrypt certificates for services
868
* "rook with ceph rbd + cephfs":https://rook.io/ for storage
869
** rbd for almost everything, *ReadWriteOnce*
870
** cephfs for smaller things, multi access *ReadWriteMany*
871
** Needed for providing persistent storage
872
* "flux v2":https://fluxcd.io/
873
** Needed to manage resources automatically