@xdev-asia/xdev-knowledge-mcp 1.0.52 → 1.0.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/data/quizzes/cka.json +319 -0
- package/data/quizzes/ckad.json +318 -0
- package/data/quizzes/gcp-ml-engineer.json +608 -100
- package/data/quizzes/kcna.json +317 -0
- package/data/quizzes.json +49 -4
- package/package.json +1 -1
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "cka",
|
|
3
|
+
"title": "CKA — Certified Kubernetes Administrator",
|
|
4
|
+
"slug": "cka",
|
|
5
|
+
"description": "Practice exam for CKA — 20 questions covering all 5 domains",
|
|
6
|
+
"icon": "award",
|
|
7
|
+
"provider": "CNCF",
|
|
8
|
+
"level": "Professional",
|
|
9
|
+
"duration_minutes": 45,
|
|
10
|
+
"passing_score": 66,
|
|
11
|
+
"questions_count": 20,
|
|
12
|
+
"tags": ["Kubernetes", "CKA", "CNCF", "DevOps", "Linux Foundation"],
|
|
13
|
+
"series_slug": "luyen-thi-cka",
|
|
14
|
+
"domains": [
|
|
15
|
+
{
|
|
16
|
+
"name": "Domain 1: Cluster Architecture, Installation & Configuration",
|
|
17
|
+
"weight": 25,
|
|
18
|
+
"lessons": [
|
|
19
|
+
{ "title": "Bài 1: Kubernetes Architecture & kubeadm Cluster Setup", "slug": "01-kien-truc-cka-kubeadm" },
|
|
20
|
+
{ "title": "Bài 2: Cluster Upgrade với kubeadm", "slug": "02-cluster-upgrade-kubeadm" },
|
|
21
|
+
{ "title": "Bài 3: RBAC — Role-Based Access Control", "slug": "03-rbac-cka" }
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"name": "Domain 2: Workloads & Scheduling",
|
|
26
|
+
"weight": 15,
|
|
27
|
+
"lessons": [
|
|
28
|
+
{ "title": "Bài 4: Deployments, DaemonSets & StatefulSets", "slug": "04-deployments-daemonsets-statefulsets" },
|
|
29
|
+
{ "title": "Bài 5: Scheduling — Taints, Tolerations & Affinity", "slug": "05-scheduling-taints-affinity" }
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"name": "Domain 3: Services & Networking",
|
|
34
|
+
"weight": 20,
|
|
35
|
+
"lessons": [
|
|
36
|
+
{ "title": "Bài 6: Services, Endpoints & CoreDNS", "slug": "06-services-endpoints-coredns" },
|
|
37
|
+
{ "title": "Bài 7: Ingress, Network Policies & CNI", "slug": "07-ingress-networkpolicies-cni" }
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"name": "Domain 4: Storage",
|
|
42
|
+
"weight": 10,
|
|
43
|
+
"lessons": [
|
|
44
|
+
{ "title": "Bài 8: Persistent Volumes, PVCs & StorageClass", "slug": "08-persistent-volumes-storageclass" }
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"name": "Domain 5: Troubleshooting",
|
|
49
|
+
"weight": 30,
|
|
50
|
+
"lessons": [
|
|
51
|
+
{ "title": "Bài 9: etcd Backup & Restore", "slug": "09-etcd-backup-restore" },
|
|
52
|
+
{ "title": "Bài 10: Troubleshooting Nodes & Cluster", "slug": "10-troubleshooting-nodes" },
|
|
53
|
+
{ "title": "Bài 11: Troubleshooting Workloads", "slug": "11-troubleshooting-workloads" }
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
"questions": [
|
|
58
|
+
{
|
|
59
|
+
"id": 1,
|
|
60
|
+
"domain": "Domain 1: Cluster Architecture, Installation & Configuration",
|
|
61
|
+
"question": "You need to upgrade a Kubernetes cluster from v1.29 to v1.30 using kubeadm. What is the CORRECT order of operations?",
|
|
62
|
+
"options": [
|
|
63
|
+
"Upgrade worker nodes first, then upgrade control plane",
|
|
64
|
+
"Upgrade kubeadm on control plane, run kubeadm upgrade plan/apply, upgrade kubelet and kubectl, then upgrade worker nodes",
|
|
65
|
+
"Upgrade kubelet on all nodes simultaneously",
|
|
66
|
+
"Upgrade kubectl first, then kubeadm, then kubelet"
|
|
67
|
+
],
|
|
68
|
+
"correct": 1,
|
|
69
|
+
"explanation": "The correct upgrade order is: upgrade kubeadm → run kubeadm upgrade plan → kubeadm upgrade apply on the control plane → upgrade kubelet and kubectl on control plane → then repeat for each worker node (drain, upgrade kubeadm/kubelet, uncordon)."
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"id": 2,
|
|
73
|
+
"domain": "Domain 1: Cluster Architecture, Installation & Configuration",
|
|
74
|
+
"question": "Which kubectl command checks if a user has permission to create deployments in the 'production' namespace?",
|
|
75
|
+
"options": [
|
|
76
|
+
"kubectl get roles -n production",
|
|
77
|
+
"kubectl auth can-i create deployments -n production",
|
|
78
|
+
"kubectl describe clusterrole admin",
|
|
79
|
+
"kubectl check-access deployments -n production"
|
|
80
|
+
],
|
|
81
|
+
"correct": 1,
|
|
82
|
+
"explanation": "kubectl auth can-i checks whether an action is allowed. 'kubectl auth can-i create deployments -n production' checks if the current user can create deployments in the production namespace."
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"id": 3,
|
|
86
|
+
"domain": "Domain 1: Cluster Architecture, Installation & Configuration",
|
|
87
|
+
"question": "A RoleBinding binds a ClusterRole to a user in namespace 'dev'. What is the scope of the permissions?",
|
|
88
|
+
"options": [
|
|
89
|
+
"Cluster-wide, because ClusterRole is cluster-scoped",
|
|
90
|
+
"Limited to the 'dev' namespace only",
|
|
91
|
+
"All namespaces except 'dev'",
|
|
92
|
+
"It will result in an error — ClusterRole cannot be used with RoleBinding"
|
|
93
|
+
],
|
|
94
|
+
"correct": 1,
|
|
95
|
+
"explanation": "When a RoleBinding references a ClusterRole, the permissions are scoped to the RoleBinding's namespace only. This is a common pattern to reuse a set of permissions defined in a ClusterRole across multiple namespaces."
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"id": 4,
|
|
99
|
+
"domain": "Domain 1: Cluster Architecture, Installation & Configuration",
|
|
100
|
+
"question": "What is the Kubernetes version skew policy for kubelet relative to kube-apiserver?",
|
|
101
|
+
"options": [
|
|
102
|
+
"kubelet must be the exact same version as kube-apiserver",
|
|
103
|
+
"kubelet can be up to 3 minor versions older than kube-apiserver",
|
|
104
|
+
"kubelet can be up to 2 minor versions older than kube-apiserver, but not newer",
|
|
105
|
+
"There is no version requirement between kubelet and kube-apiserver"
|
|
106
|
+
],
|
|
107
|
+
"correct": 2,
|
|
108
|
+
"explanation": "kubelet may be up to two minor versions older than kube-apiserver but must not be newer. For example, kube-apiserver 1.30 supports kubelet 1.28, 1.29, and 1.30."
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"id": 5,
|
|
112
|
+
"domain": "Domain 2: Workloads & Scheduling",
|
|
113
|
+
"question": "A pod is in 'Pending' state. kubectl describe shows 'insufficient cpu'. What is the MOST likely cause?",
|
|
114
|
+
"options": [
|
|
115
|
+
"The container image is too large",
|
|
116
|
+
"No node has enough allocatable CPU to satisfy the pod's resource requests",
|
|
117
|
+
"The pod has a failed liveness probe",
|
|
118
|
+
"The pod's service account doesn't have sufficient permissions"
|
|
119
|
+
],
|
|
120
|
+
"correct": 1,
|
|
121
|
+
"explanation": "When a pod is Pending with 'insufficient cpu', it means the scheduler cannot find a node with enough available CPU resources to satisfy the pod's resource requests. Solutions include adding nodes, reducing requests, or removing resource-heavy pods."
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"id": 6,
|
|
125
|
+
"domain": "Domain 2: Workloads & Scheduling",
|
|
126
|
+
"question": "How do you ensure a pod is scheduled ONLY on nodes with the label 'disk=ssd'?",
|
|
127
|
+
"options": [
|
|
128
|
+
"Use a taint on the nodes with disk=ssd",
|
|
129
|
+
"Use nodeSelector with disk: ssd in the pod spec",
|
|
130
|
+
"Use a PodDisruptionBudget",
|
|
131
|
+
"Use podAntiAffinity"
|
|
132
|
+
],
|
|
133
|
+
"correct": 1,
|
|
134
|
+
"explanation": "nodeSelector is the simplest way to constrain pods to nodes with specific labels. Adding 'nodeSelector: { disk: ssd }' to the pod spec ensures the pod is only scheduled on nodes with that label."
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"id": 7,
|
|
138
|
+
"domain": "Domain 2: Workloads & Scheduling",
|
|
139
|
+
"question": "What is the effect of adding a taint 'key=value:NoSchedule' to a node?",
|
|
140
|
+
"options": [
|
|
141
|
+
"All existing pods without a matching toleration are evicted immediately",
|
|
142
|
+
"No new pods will be scheduled on the node unless they have a matching toleration",
|
|
143
|
+
"The node is removed from the cluster",
|
|
144
|
+
"All pods on the node are restarted"
|
|
145
|
+
],
|
|
146
|
+
"correct": 1,
|
|
147
|
+
"explanation": "NoSchedule prevents new pods without a matching toleration from being scheduled on the node. Existing pods are NOT affected. Use NoExecute to also evict existing non-tolerating pods."
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
"id": 8,
|
|
151
|
+
"domain": "Domain 3: Services & Networking",
|
|
152
|
+
"question": "What is the DNS format for resolving a Service named 'my-svc' in namespace 'my-ns'?",
|
|
153
|
+
"options": [
|
|
154
|
+
"my-svc.my-ns",
|
|
155
|
+
"my-svc.my-ns.svc.cluster.local",
|
|
156
|
+
"my-ns.my-svc.cluster.local",
|
|
157
|
+
"svc.my-svc.my-ns.cluster.local"
|
|
158
|
+
],
|
|
159
|
+
"correct": 1,
|
|
160
|
+
"explanation": "Kubernetes DNS follows the format: <service-name>.<namespace>.svc.cluster.local. Within the same namespace, you can use just the service name. Across namespaces, use <service-name>.<namespace>."
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"id": 9,
|
|
164
|
+
"domain": "Domain 3: Services & Networking",
|
|
165
|
+
"question": "An Ingress resource routes traffic to a backend service. The Ingress controller pod is running but rules are not taking effect. What should you check FIRST?",
|
|
166
|
+
"options": [
|
|
167
|
+
"Whether the Ingress has the correct ingressClassName",
|
|
168
|
+
"Whether etcd is healthy",
|
|
169
|
+
"Whether the node has enough memory",
|
|
170
|
+
"Whether kube-scheduler is running"
|
|
171
|
+
],
|
|
172
|
+
"correct": 0,
|
|
173
|
+
"explanation": "If Ingress rules are not working despite the controller running, the first check should be ingressClassName. In Kubernetes 1.22+, Ingress resources need to specify the correct IngressClass to be picked up by the right controller."
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"id": 10,
|
|
177
|
+
"domain": "Domain 3: Services & Networking",
|
|
178
|
+
"question": "You created a NetworkPolicy with an empty podSelector {}. What is the effect?",
|
|
179
|
+
"options": [
|
|
180
|
+
"It selects no pods in the namespace",
|
|
181
|
+
"It selects all pods in the namespace",
|
|
182
|
+
"It causes a validation error",
|
|
183
|
+
"It applies to the entire cluster"
|
|
184
|
+
],
|
|
185
|
+
"correct": 1,
|
|
186
|
+
"explanation": "An empty podSelector {} selects ALL pods in the namespace. A NetworkPolicy with spec.podSelector: {} and no ingress/egress rules effectively creates a default-deny policy for all pods in that namespace."
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"id": 11,
|
|
190
|
+
"domain": "Domain 3: Services & Networking",
|
|
191
|
+
"question": "Which kube-proxy mode is MOST performant for large clusters with many Services?",
|
|
192
|
+
"options": [
|
|
193
|
+
"userspace mode",
|
|
194
|
+
"iptables mode",
|
|
195
|
+
"IPVS mode",
|
|
196
|
+
"nftables mode"
|
|
197
|
+
],
|
|
198
|
+
"correct": 2,
|
|
199
|
+
"explanation": "IPVS (IP Virtual Server) mode uses hash tables for Service-to-Pod mapping, providing O(1) lookup performance regardless of the number of Services, making it much more efficient than iptables for large clusters."
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"id": 12,
|
|
203
|
+
"domain": "Domain 4: Storage",
|
|
204
|
+
"question": "A PersistentVolume has reclaimPolicy set to 'Retain'. What happens when the associated PVC is deleted?",
|
|
205
|
+
"options": [
|
|
206
|
+
"The PV and its data are automatically deleted",
|
|
207
|
+
"The PV remains with its data intact but it becomes 'Released' and cannot be bound to a new PVC without manual intervention",
|
|
208
|
+
"The PV is immediately available for a new PVC to claim",
|
|
209
|
+
"The data is archived to an object store"
|
|
210
|
+
],
|
|
211
|
+
"correct": 1,
|
|
212
|
+
"explanation": "With Retain policy, when the PVC is deleted, the PV enters 'Released' state. The data is preserved, but the PV cannot be rebound automatically. An admin must manually clean up and reconfigure the PV for reuse."
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
"id": 13,
|
|
216
|
+
"domain": "Domain 4: Storage",
|
|
217
|
+
"question": "Which access mode allows a PersistentVolume to be mounted as read-write by multiple nodes simultaneously?",
|
|
218
|
+
"options": [
|
|
219
|
+
"ReadWriteOnce (RWO)",
|
|
220
|
+
"ReadOnlyMany (ROX)",
|
|
221
|
+
"ReadWriteMany (RWX)",
|
|
222
|
+
"ReadWriteOncePod (RWOP)"
|
|
223
|
+
],
|
|
224
|
+
"correct": 2,
|
|
225
|
+
"explanation": "ReadWriteMany (RWX) allows the volume to be mounted as read-write by many nodes simultaneously. This is commonly supported by network file systems like NFS, CephFS, and cloud-native shared file storage."
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
"id": 14,
|
|
229
|
+
"domain": "Domain 5: Troubleshooting",
|
|
230
|
+
"question": "You need to take a snapshot of etcd for backup. Which tool and flags are required?",
|
|
231
|
+
"options": [
|
|
232
|
+
"kubectl backup etcd --output=/backup/snapshot.db",
|
|
233
|
+
"etcdctl snapshot save /backup/snapshot.db --endpoints --cacert --cert --key",
|
|
234
|
+
"kubeadm backup etcd --snapshot-dir=/backup",
|
|
235
|
+
"etcdctl backup --data-dir=/var/lib/etcd"
|
|
236
|
+
],
|
|
237
|
+
"correct": 1,
|
|
238
|
+
"explanation": "etcdctl snapshot save is the correct command. It requires TLS flags: --endpoints (etcd address), --cacert (CA certificate), --cert (server certificate), and --key (server key), all found in the etcd pod manifest."
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"id": 15,
|
|
242
|
+
"domain": "Domain 5: Troubleshooting",
|
|
243
|
+
"question": "A node shows 'NotReady' status. Which is the FIRST thing to check?",
|
|
244
|
+
"options": [
|
|
245
|
+
"Check if kube-proxy is running",
|
|
246
|
+
"Check if kubelet is running on the node (systemctl status kubelet)",
|
|
247
|
+
"Check if CoreDNS pods are healthy",
|
|
248
|
+
"Check if the container images are cached"
|
|
249
|
+
],
|
|
250
|
+
"correct": 1,
|
|
251
|
+
"explanation": "A NotReady node typically means kubelet is not communicating with the API server. The first step is to SSH into the node and check kubelet status with 'systemctl status kubelet', then check logs with 'journalctl -u kubelet'."
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
"id": 16,
|
|
255
|
+
"domain": "Domain 5: Troubleshooting",
|
|
256
|
+
"question": "A pod is in CrashLoopBackOff state. Which command is MOST useful to diagnose the issue?",
|
|
257
|
+
"options": [
|
|
258
|
+
"kubectl get events",
|
|
259
|
+
"kubectl logs <pod-name> --previous",
|
|
260
|
+
"kubectl describe node",
|
|
261
|
+
"kubectl top pod"
|
|
262
|
+
],
|
|
263
|
+
"correct": 1,
|
|
264
|
+
"explanation": "kubectl logs <pod-name> --previous shows logs from the previous crashed container instance. This reveals the actual error (e.g., application error, missing config) that caused the crash."
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
"id": 17,
|
|
268
|
+
"domain": "Domain 5: Troubleshooting",
|
|
269
|
+
"question": "A Deployment's pods cannot reach a ClusterIP Service. The Service has endpoints. What should you check?",
|
|
270
|
+
"options": [
|
|
271
|
+
"Whether the Service has the correct selector matching the pod labels",
|
|
272
|
+
"Whether there's a NetworkPolicy blocking traffic between the source pods and the Service",
|
|
273
|
+
"Whether the Deployment has enough replicas",
|
|
274
|
+
"Whether the node has sufficient disk space"
|
|
275
|
+
],
|
|
276
|
+
"correct": 1,
|
|
277
|
+
"explanation": "If the Service has endpoints (backends are matched), but pods can't reach it, a NetworkPolicy may be blocking traffic. Check for NetworkPolicies in both the source and destination namespaces that could restrict ingress or egress."
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
"id": 18,
|
|
281
|
+
"domain": "Domain 5: Troubleshooting",
|
|
282
|
+
"question": "After restoring etcd from a snapshot, the API server shows stale data. What is the MOST likely cause?",
|
|
283
|
+
"options": [
|
|
284
|
+
"The snapshot file was corrupted",
|
|
285
|
+
"The etcd data-dir was not updated to point to the restored snapshot location",
|
|
286
|
+
"kube-apiserver needs a version upgrade",
|
|
287
|
+
"CoreDNS needs to be restarted"
|
|
288
|
+
],
|
|
289
|
+
"correct": 1,
|
|
290
|
+
"explanation": "After restoring, you must update the etcd pod manifest (or systemd unit) to point --data-dir to the new restored directory. If the old data-dir is still being used, etcd will serve stale data."
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
"id": 19,
|
|
294
|
+
"domain": "Domain 5: Troubleshooting",
|
|
295
|
+
"question": "A pod is stuck in 'ImagePullBackOff' state. Which is NOT a possible cause?",
|
|
296
|
+
"options": [
|
|
297
|
+
"The image name or tag is incorrect",
|
|
298
|
+
"The container registry requires authentication and no imagePullSecret is configured",
|
|
299
|
+
"The node has insufficient CPU resources",
|
|
300
|
+
"Network connectivity to the registry is blocked"
|
|
301
|
+
],
|
|
302
|
+
"correct": 2,
|
|
303
|
+
"explanation": "ImagePullBackOff indicates the kubelet cannot pull the container image. This can be due to wrong image name, missing registry credentials, or network issues — but NOT CPU resources. CPU issues cause Pending state, not ImagePullBackOff."
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
"id": 20,
|
|
307
|
+
"domain": "Domain 5: Troubleshooting",
|
|
308
|
+
"question": "How would you check which static pod manifests are being used on a node?",
|
|
309
|
+
"options": [
|
|
310
|
+
"kubectl get staticpods",
|
|
311
|
+
"Check the directory specified by kubelet's --pod-manifest-path flag (default: /etc/kubernetes/manifests/)",
|
|
312
|
+
"kubectl describe node | grep StaticPods",
|
|
313
|
+
"etcdctl get /registry/pods"
|
|
314
|
+
],
|
|
315
|
+
"correct": 1,
|
|
316
|
+
"explanation": "Static pods are defined by manifest files in the directory configured via --pod-manifest-path (default /etc/kubernetes/manifests/). kubelet watches this directory and automatically creates/deletes pods based on these manifests."
|
|
317
|
+
}
|
|
318
|
+
]
|
|
319
|
+
}
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "ckad",
|
|
3
|
+
"title": "CKAD — Certified Kubernetes Application Developer",
|
|
4
|
+
"slug": "ckad",
|
|
5
|
+
"description": "Practice exam for CKAD — 20 questions covering all 5 domains",
|
|
6
|
+
"icon": "award",
|
|
7
|
+
"provider": "CNCF",
|
|
8
|
+
"level": "Professional",
|
|
9
|
+
"duration_minutes": 45,
|
|
10
|
+
"passing_score": 66,
|
|
11
|
+
"questions_count": 20,
|
|
12
|
+
"tags": ["Kubernetes", "CKAD", "CNCF", "DevOps", "Linux Foundation"],
|
|
13
|
+
"series_slug": "luyen-thi-ckad",
|
|
14
|
+
"domains": [
|
|
15
|
+
{
|
|
16
|
+
"name": "Domain 1: Application Design and Build",
|
|
17
|
+
"weight": 20,
|
|
18
|
+
"lessons": [
|
|
19
|
+
{ "title": "Bài 1: Container Images & Multi-stage Builds", "slug": "01-container-images-multi-stage" },
|
|
20
|
+
{ "title": "Bài 2: Pod Design — Labels, Selectors, Annotations", "slug": "02-pod-design-labels-selectors" }
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"name": "Domain 2: Application Deployment",
|
|
25
|
+
"weight": 20,
|
|
26
|
+
"lessons": [
|
|
27
|
+
{ "title": "Bài 3: Deployments, Rolling Updates & Rollbacks", "slug": "03-deployments-rolling-updates" },
|
|
28
|
+
{ "title": "Bài 4: Helm Basics — Charts, Releases, Repositories", "slug": "04-helm-basics" }
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"name": "Domain 3: Application Observability and Maintenance",
|
|
33
|
+
"weight": 15,
|
|
34
|
+
"lessons": [
|
|
35
|
+
{ "title": "Bài 5: Probes — Liveness, Readiness, Startup", "slug": "05-probes-liveness-readiness" },
|
|
36
|
+
{ "title": "Bài 6: Logging, Monitoring & Debugging", "slug": "06-logging-monitoring-debugging" }
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "Domain 4: Application Environment, Configuration and Security",
|
|
41
|
+
"weight": 25,
|
|
42
|
+
"lessons": [
|
|
43
|
+
{ "title": "Bài 7: ConfigMaps & Secrets", "slug": "07-configmaps-secrets" },
|
|
44
|
+
{ "title": "Bài 8: ServiceAccounts & Security Contexts", "slug": "08-serviceaccounts-security" },
|
|
45
|
+
{ "title": "Bài 9: Resource Requests, Limits & LimitRanges", "slug": "09-resource-requests-limits" }
|
|
46
|
+
]
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"name": "Domain 5: Services and Networking",
|
|
50
|
+
"weight": 20,
|
|
51
|
+
"lessons": [
|
|
52
|
+
{ "title": "Bài 10: Services, Ingress & Network Policies", "slug": "10-services-ingress-networkpolicies" }
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
"questions": [
|
|
57
|
+
{
|
|
58
|
+
"id": 1,
|
|
59
|
+
"domain": "Domain 1: Application Design and Build",
|
|
60
|
+
"question": "Which Dockerfile instruction is used to set the command that runs when the container starts, and CAN be overridden by the user at runtime?",
|
|
61
|
+
"options": [
|
|
62
|
+
"ENTRYPOINT",
|
|
63
|
+
"CMD",
|
|
64
|
+
"RUN",
|
|
65
|
+
"EXPOSE"
|
|
66
|
+
],
|
|
67
|
+
"correct": 1,
|
|
68
|
+
"explanation": "CMD sets the default command for the container, which can be overridden by passing arguments to docker run or in the Kubernetes pod spec's command/args fields. ENTRYPOINT sets the main executable and is harder to override."
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"id": 2,
|
|
72
|
+
"domain": "Domain 1: Application Design and Build",
|
|
73
|
+
"question": "What is the benefit of a multi-stage Docker build?",
|
|
74
|
+
"options": [
|
|
75
|
+
"It allows running multiple containers in a single pod",
|
|
76
|
+
"It reduces the final image size by separating build-time dependencies from runtime",
|
|
77
|
+
"It enables horizontal pod autoscaling",
|
|
78
|
+
"It automatically creates Kubernetes manifests"
|
|
79
|
+
],
|
|
80
|
+
"correct": 1,
|
|
81
|
+
"explanation": "Multi-stage builds use multiple FROM instructions. Build tools and dependencies stay in earlier stages while only the compiled artifact is copied to the final, minimal runtime image — significantly reducing image size."
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"id": 3,
|
|
85
|
+
"domain": "Domain 1: Application Design and Build",
|
|
86
|
+
"question": "You want to select all pods with label 'app=web' AND 'tier=frontend'. Which label selector syntax is correct?",
|
|
87
|
+
"options": [
|
|
88
|
+
"app=web || tier=frontend",
|
|
89
|
+
"app=web,tier=frontend",
|
|
90
|
+
"app=web AND tier=frontend",
|
|
91
|
+
"app=web;tier=frontend"
|
|
92
|
+
],
|
|
93
|
+
"correct": 1,
|
|
94
|
+
"explanation": "In Kubernetes, multiple label selectors are comma-separated. 'app=web,tier=frontend' selects pods that have BOTH labels. This is used in kubectl: 'kubectl get pods -l app=web,tier=frontend'."
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"id": 4,
|
|
98
|
+
"domain": "Domain 1: Application Design and Build",
|
|
99
|
+
"question": "How do you create a CronJob that runs every day at 3:00 AM?",
|
|
100
|
+
"options": [
|
|
101
|
+
"schedule: '3 0 * * *'",
|
|
102
|
+
"schedule: '0 3 * * *'",
|
|
103
|
+
"schedule: '* * 3 * *'",
|
|
104
|
+
"schedule: 'daily 3:00'"
|
|
105
|
+
],
|
|
106
|
+
"correct": 1,
|
|
107
|
+
"explanation": "Cron format is: minute hour day-of-month month day-of-week. '0 3 * * *' means at minute 0, hour 3 (3:00 AM), every day of month, every month, every day of week."
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"id": 5,
|
|
111
|
+
"domain": "Domain 2: Application Deployment",
|
|
112
|
+
"question": "A Deployment with 4 replicas uses the RollingUpdate strategy with maxSurge=1 and maxUnavailable=0. How many pods exist during an update?",
|
|
113
|
+
"options": [
|
|
114
|
+
"Exactly 4 pods at all times",
|
|
115
|
+
"Up to 5 pods (4 desired + 1 surge)",
|
|
116
|
+
"Between 3 and 5 pods",
|
|
117
|
+
"Up to 8 pods (doubled)"
|
|
118
|
+
],
|
|
119
|
+
"correct": 1,
|
|
120
|
+
"explanation": "maxSurge=1 allows one extra pod above the desired count (4+1=5). maxUnavailable=0 means all 4 desired pods must remain available. So Kubernetes creates a new pod first, waits for it to be ready, then terminates an old one."
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"id": 6,
|
|
124
|
+
"domain": "Domain 2: Application Deployment",
|
|
125
|
+
"question": "How do you rollback a Deployment named 'web-app' to its previous version?",
|
|
126
|
+
"options": [
|
|
127
|
+
"kubectl rollback deployment web-app",
|
|
128
|
+
"kubectl rollout undo deployment web-app",
|
|
129
|
+
"kubectl revert deployment web-app",
|
|
130
|
+
"kubectl apply --previous deployment web-app"
|
|
131
|
+
],
|
|
132
|
+
"correct": 1,
|
|
133
|
+
"explanation": "kubectl rollout undo deployment <name> rolls back to the previous revision. You can also specify a revision with --to-revision=N. Use 'kubectl rollout history' to view available revisions."
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"id": 7,
|
|
137
|
+
"domain": "Domain 2: Application Deployment",
|
|
138
|
+
"question": "You installed a Helm chart with 'helm install my-release bitnami/nginx'. How do you update the release with new values?",
|
|
139
|
+
"options": [
|
|
140
|
+
"helm update my-release bitnami/nginx -f values.yaml",
|
|
141
|
+
"helm upgrade my-release bitnami/nginx -f values.yaml",
|
|
142
|
+
"helm apply my-release bitnami/nginx -f values.yaml",
|
|
143
|
+
"helm install --upgrade my-release bitnami/nginx -f values.yaml"
|
|
144
|
+
],
|
|
145
|
+
"correct": 1,
|
|
146
|
+
"explanation": "helm upgrade is used to update an existing release with new chart versions or values. The -f flag specifies a custom values file. Use --install flag to install if the release doesn't exist yet."
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"id": 8,
|
|
150
|
+
"domain": "Domain 2: Application Deployment",
|
|
151
|
+
"question": "What does a Blue-Green deployment strategy ensure?",
|
|
152
|
+
"options": [
|
|
153
|
+
"Traffic is gradually shifted from old to new version",
|
|
154
|
+
"Two complete environments exist, and traffic is switched entirely from one to the other",
|
|
155
|
+
"Only one pod is updated at a time",
|
|
156
|
+
"The deployment is paused until manually approved"
|
|
157
|
+
],
|
|
158
|
+
"correct": 1,
|
|
159
|
+
"explanation": "Blue-Green deployment maintains two identical environments (Blue=current, Green=new). Once the Green environment is verified, traffic is switched entirely to Green. This enables instant rollback by switching back to Blue."
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"id": 9,
|
|
163
|
+
"domain": "Domain 3: Application Observability and Maintenance",
|
|
164
|
+
"question": "A pod's readinessProbe fails. What is the consequence?",
|
|
165
|
+
"options": [
|
|
166
|
+
"The pod is restarted",
|
|
167
|
+
"The pod is removed from the Service's endpoints (stops receiving traffic)",
|
|
168
|
+
"The pod is deleted and a new one is created",
|
|
169
|
+
"The node is marked as NotReady"
|
|
170
|
+
],
|
|
171
|
+
"correct": 1,
|
|
172
|
+
"explanation": "When a readinessProbe fails, the pod is removed from Service endpoints and stops receiving traffic. Unlike livenessProbe, a failed readinessProbe does NOT restart the pod — it just marks it as not ready to serve."
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"id": 10,
|
|
176
|
+
"domain": "Domain 3: Application Observability and Maintenance",
|
|
177
|
+
"question": "Which probe type should you use for a container that takes a long time to start up?",
|
|
178
|
+
"options": [
|
|
179
|
+
"livenessProbe with a high initialDelaySeconds",
|
|
180
|
+
"readinessProbe with failureThreshold=100",
|
|
181
|
+
"startupProbe",
|
|
182
|
+
"execProbe"
|
|
183
|
+
],
|
|
184
|
+
"correct": 2,
|
|
185
|
+
"explanation": "startupProbe is specifically designed for slow-starting containers. When defined, it disables liveness and readiness checks until the container starts successfully. This prevents premature restarts by the livenessProbe."
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"id": 11,
|
|
189
|
+
"domain": "Domain 3: Application Observability and Maintenance",
|
|
190
|
+
"question": "How do you view real-time logs from multiple pods of a Deployment named 'api'?",
|
|
191
|
+
"options": [
|
|
192
|
+
"kubectl logs deployment/api --all",
|
|
193
|
+
"kubectl logs -l app=api --follow",
|
|
194
|
+
"kubectl exec deployment/api -- tail -f /var/log/app.log",
|
|
195
|
+
"kubectl describe deployment api | grep logs"
|
|
196
|
+
],
|
|
197
|
+
"correct": 1,
|
|
198
|
+
"explanation": "kubectl logs -l <label-selector> streams logs from all pods matching the label. --follow (-f) enables real-time streaming. This is useful for debugging across multiple replicas simultaneously."
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"id": 12,
|
|
202
|
+
"domain": "Domain 4: Application Environment, Configuration and Security",
|
|
203
|
+
"question": "How do you create a ConfigMap from a file named 'app.properties'?",
|
|
204
|
+
"options": [
|
|
205
|
+
"kubectl create configmap my-config --from-file=app.properties",
|
|
206
|
+
"kubectl apply configmap my-config --file=app.properties",
|
|
207
|
+
"kubectl create secret generic my-config --from-file=app.properties",
|
|
208
|
+
"kubectl create configmap my-config --data=app.properties"
|
|
209
|
+
],
|
|
210
|
+
"correct": 0,
|
|
211
|
+
"explanation": "kubectl create configmap --from-file=<filename> creates a ConfigMap with the file's content. The key defaults to the filename. Use --from-file=<key>=<filename> to specify a custom key."
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
"id": 13,
|
|
215
|
+
"domain": "Domain 4: Application Environment, Configuration and Security",
|
|
216
|
+
"question": "What is the difference between a ConfigMap and a Secret in terms of data storage?",
|
|
217
|
+
"options": [
|
|
218
|
+
"Secrets are encrypted at rest by default, ConfigMaps are not",
|
|
219
|
+
"Secrets store data as base64-encoded strings, ConfigMaps store plain text",
|
|
220
|
+
"ConfigMaps can only store key-value pairs, Secrets can store files",
|
|
221
|
+
"There is no difference, they are interchangeable"
|
|
222
|
+
],
|
|
223
|
+
"correct": 1,
|
|
224
|
+
"explanation": "Secrets store data as base64-encoded strings (not encrypted by default). etcd encryption at rest must be configured separately. ConfigMaps store plain text data. Both can be mounted as volumes or used as environment variables."
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
"id": 14,
|
|
228
|
+
"domain": "Domain 4: Application Environment, Configuration and Security",
|
|
229
|
+
"question": "A pod's SecurityContext has 'runAsNonRoot: true'. What happens if the container image runs as root by default?",
|
|
230
|
+
"options": [
|
|
231
|
+
"The container runs as root anyway",
|
|
232
|
+
"The pod fails to start with a security validation error",
|
|
233
|
+
"Kubernetes automatically assigns a random non-root UID",
|
|
234
|
+
"The runAsNonRoot setting is ignored"
|
|
235
|
+
],
|
|
236
|
+
"correct": 1,
|
|
237
|
+
"explanation": "With runAsNonRoot: true, if the container's image is configured to run as root (UID 0) and no runAsUser is specified, the pod will fail to start. You must either set runAsUser to a non-root UID or use an image that runs as non-root."
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
"id": 15,
|
|
241
|
+
"domain": "Domain 4: Application Environment, Configuration and Security",
|
|
242
|
+
"question": "What happens when a container exceeds its memory LIMIT?",
|
|
243
|
+
"options": [
|
|
244
|
+
"The container is throttled to the limit",
|
|
245
|
+
"The container is OOMKilled (Out of Memory Killed)",
|
|
246
|
+
"A warning event is generated but the container continues",
|
|
247
|
+
"The pod is rescheduled to a node with more memory"
|
|
248
|
+
],
|
|
249
|
+
"correct": 1,
|
|
250
|
+
"explanation": "When a container exceeds its memory limit, the kernel's OOM killer terminates it (OOMKilled). This is different from CPU limits, where the container is throttled rather than killed. Kubernetes then restarts the container based on restartPolicy."
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
"id": 16,
|
|
254
|
+
"domain": "Domain 4: Application Environment, Configuration and Security",
|
|
255
|
+
"question": "How do you mount a specific key from a ConfigMap as a file in a pod?",
|
|
256
|
+
"options": [
|
|
257
|
+
"Use volumeMounts with subPath matching the key name",
|
|
258
|
+
"Use env.valueFrom.configMapKeyRef",
|
|
259
|
+
"ConfigMaps can only be mounted as entire directories",
|
|
260
|
+
"Use configMap.items with key and path in the volume definition"
|
|
261
|
+
],
|
|
262
|
+
"correct": 3,
|
|
263
|
+
"explanation": "In the volume definition, use configMap.items to specify which keys to include and their file paths. For example: items: [{key: 'app.conf', path: 'app.conf'}]. SubPath can also be used in volumeMounts for single-key mounting."
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"id": 17,
|
|
267
|
+
"domain": "Domain 5: Services and Networking",
|
|
268
|
+
"question": "What is the difference between a ClusterIP and a NodePort Service?",
|
|
269
|
+
"options": [
|
|
270
|
+
"ClusterIP exposes the service externally, NodePort is internal only",
|
|
271
|
+
"ClusterIP is accessible only within the cluster, NodePort exposes the service on each node's IP at a static port",
|
|
272
|
+
"ClusterIP uses TCP, NodePort uses UDP",
|
|
273
|
+
"ClusterIP requires an Ingress, NodePort does not"
|
|
274
|
+
],
|
|
275
|
+
"correct": 1,
|
|
276
|
+
"explanation": "ClusterIP (default) creates an internal-only virtual IP. NodePort exposes the service on each node's IP at a port in the range 30000-32767, making it accessible from outside the cluster via <NodeIP>:<NodePort>."
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
"id": 18,
|
|
280
|
+
"domain": "Domain 5: Services and Networking",
|
|
281
|
+
"question": "An Ingress resource routes '/api' to service 'api-svc' and '/web' to service 'web-svc'. Which annotation controls URL rewriting in nginx ingress?",
|
|
282
|
+
"options": [
|
|
283
|
+
"nginx.ingress.kubernetes.io/rewrite-target: /",
|
|
284
|
+
"nginx.ingress.kubernetes.io/url-rewrite: true",
|
|
285
|
+
"nginx.ingress.kubernetes.io/path-redirect: /",
|
|
286
|
+
"nginx.ingress.kubernetes.io/backend-path: /"
|
|
287
|
+
],
|
|
288
|
+
"correct": 0,
|
|
289
|
+
"explanation": "nginx.ingress.kubernetes.io/rewrite-target controls the URL rewriting. Setting it to '/' rewrites the matched path to '/'. For example, a request to '/api/users' would be forwarded to the backend as '/users'."
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
"id": 19,
|
|
293
|
+
"domain": "Domain 5: Services and Networking",
|
|
294
|
+
"question": "A NetworkPolicy allows ingress only from pods with label 'role=frontend' on port 8080. A pod with label 'role=backend' tries to connect on port 8080. What happens?",
|
|
295
|
+
"options": [
|
|
296
|
+
"The connection is allowed because port 8080 is open",
|
|
297
|
+
"The connection is denied because the source pod doesn't match the ingress rule",
|
|
298
|
+
"The NetworkPolicy is ignored because it only affects egress",
|
|
299
|
+
"The connection times out only if the CNI plugin doesn't support NetworkPolicy"
|
|
300
|
+
],
|
|
301
|
+
"correct": 1,
|
|
302
|
+
"explanation": "NetworkPolicy ingress rules specify both 'from' (source pods/namespaces) and 'ports'. Even though port 8080 matches, the source pod doesn't have label 'role=frontend', so the connection is denied."
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
"id": 20,
|
|
306
|
+
"domain": "Domain 5: Services and Networking",
|
|
307
|
+
"question": "Which Service type automatically provisions a cloud load balancer?",
|
|
308
|
+
"options": [
|
|
309
|
+
"ClusterIP",
|
|
310
|
+
"NodePort",
|
|
311
|
+
"LoadBalancer",
|
|
312
|
+
"ExternalName"
|
|
313
|
+
],
|
|
314
|
+
"correct": 2,
|
|
315
|
+
"explanation": "LoadBalancer type automatically provisions an external load balancer (e.g., AWS ELB, GCP Load Balancer). It builds on NodePort, which builds on ClusterIP. ExternalName maps a Service to a DNS name without any proxy."
|
|
316
|
+
}
|
|
317
|
+
]
|
|
318
|
+
}
|