$ vi hello-busybox-pod.yaml
apiVersion: v1 kind: Pod metadata: name: hello-busybox # will be used as the hostname of the conatiners spec: containers: - name: hello-busybox image: busybox:latest command: ['sh', '-c', 'echo "hello, busybox!"; sleep 300;']The Pod's name must be a valid DNS subdomain name:
$ kubectl apply -f hello-busybox-pod.yaml
pod/hello-busybox createdThe "hello-busybox-pod.yaml" file defines the following fields:
command: ['sh'] args: ['-c', 'echo "hello, busybox!"; sleep 300;']
command: - sh - -c - echo "hello, busybox!"; sleep 300;
command: - sh - -c - | echo "hello, busybox!"; sleep 300;Note: Managing Pods using the Manifest Yam file (declarative) is the recommended way, but in some cases you might want to use the imperative command "kubectl create" to create a Pod.
$ kubectl run -i -t hello-busybox --image=busybox:latest -- sh-i, --stdin: Keep stdin open on the container(s) in the pod, even if nothing is attached.
$ kubectl apply -f hello-busybox-pod.yaml --dry-run=client -o yaml
apiVersion: v1 kind: Pod metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"labels":{},"name":"hello-busybox"},"spec":{"containers":[{"command":["sh","-c","echo \"hello, busybox!\"; sleep 300;"],"image":"busybox:latest","name":"hello-busybox"}]}} name: hello-busybox namespace: test spec: containers: - command: - sh - -c - echo "hello, busybox!"; sleep 300; image: busybox:latest name: hello-busyboxYou can use the "view-last-applied" flag to print the YAML file as it was applied the last time:
$ kubectl apply -f hello-busybox-pod.yaml view-last-appliedYou can edit and update the definition of a kubernetes object:
$ kubectl edit pod hello-busybox
$ kubectl get pods
NAME READY STATUS RESTARTS AGE hello-busybox 1/1 Running 0 18s
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES hello-busybox 1/1 Running 0 80s 10.1.0.9 docker-desktop <none> <none>
$ kubectl get pod hello-busybox
NAME READY STATUS RESTARTS AGE hello-busybox 1/1 Running 0 18s
$ kubectl get pods hello-busybox -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES hello-busybox 1/1 Running 0 80s 10.1.0.9 docker-desktop <none> <none>
$ kubectl get pods --watch
NAME READY STATUS RESTARTS AGE hello-busybox 0/1 ContainerCreating 0 2s hello-busybox 1/1 Running 0 17sA Pod is available when the field STATUS shows Running and the field READY shows the conainers ready (1/1). If a Pod has many containers, then the READY field should show the number of all its containers
$ kubectl exec hello-busybox -- env
HOSTNAME=hello-busybox ...-- (double dash) separate the kubectl arguments from the command (and its arguments) you want to run in the Pod.
$ kubectl exec hello-busybox -c hello-busybox -- envThe --container (-c) flag applies also to init containers.
$ kubectl exec -it hello-busybox -- sh
/ # ps PID USER TIME COMMAND 1 root 0:00 sleep 300 7 root 0:00 sh 13 root 0:00 ps / #-- (double dash) separate the kubectl arguments from the command (and its arguments) you want to run in the Pod.
$ kubectl exec -it hello-busybox -c hello-busybox -- shThe --container (-c) flag applies also to init containers.
$ kubectl logs hello-busybox
hello, busybox!If more than one container are running in the Pod, then the command will be executed against the first container in the Pod (see the command: kubectl describe pod hello-busybox). To print the logs of a specific container, you need to use the --container (-c) flag and give it the name of the container:
$ kubectl logs hello-busybox -c hello-busyboxThe --container (-c) flag applies also to init containers.
$ kubectl cp ./file1.txt hello-busybox:/tmp/file1.txtTo copy files from the Pod to the local VM:
$ kubectl cp hello-busybox:tmp/file1.txt ./file1-from-busybox-tar.txtNote that the path to the file in the Pod doesn't have the leading character '/'. This was needed to avoid this warning "tar: removing leading '/' from member names".
kubectl apply -f - <<EOF apiVersion: v1 kind: Pod metadata: name: hello-nginx spec: containers: - name: hello-nginx image: nginx:latest ports: - containerPort: 80 EOF
$ kubectl port-forward hello-nginx 8080:80
Forwarding from 127.0.0.1:8080 -> 80 Forwarding from [::1]:8080 -> 80
$ curl http://localhost:8080
<html> <head> <title>Welcome to nginx!</title> ...You can also use a Service to forward a port, but note that it will be bound to only one Pod of the Service:
$ kubectl port-forward svc/kubernetes-dashboard-kong-proxy 8443:443 -n kubernetes-dashboard
$ kubectl get pod hello-busybox -o yaml
apiVersion: v1 kind: Pod metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"labels":{},"name":"hello-busybox","namespace":"default"},"spec":{"containers":[{"args":["-c","echo \"hello, busybox!\"; sleep 300;"],"command":["sh"],"image":"busybox:latest","name":"hello-busybox"}]}} managedFields: - apiVersion: v1 ... manager: kubelet operation: Update name: hello-busybox namespace: default spec: containers: - args: - -c - echo "hello, busybox!"; sleep 300; command: - sh image: busybox:latest imagePullPolicy: Always name: hello-busybox resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File volumeMounts: - mountPath: /var/run/secrets/kubernetes.io/serviceaccount name: default-token-qvt58 readOnly: true dnsPolicy: ClusterFirst enableServiceLinks: true nodeName: docker-desktop preemptionPolicy: PreemptLowerPriority priority: 0 restartPolicy: Always schedulerName: default-scheduler securityContext: {} serviceAccount: default serviceAccountName: default terminationGracePeriodSeconds: 30 tolerations: ... volumes: - name: default-token-qvt58 secret: defaultMode: 420 secretName: default-token-qvt58 status: hostIP: 192.168.65.4 phase: Running podIP: 10.1.0.15 podIPs: - ip: 10.1.0.15 qosClass: BestEffortNote: The printed yaml object contains more settings than what it was defined in the original manifest file.
$ kubectl describe pod hello-busybox
Name: hello-busybox Namespace: default Priority: 0 Node: docker-desktop/192.168.65.4 Labels: product=mtitek stage=dev Annotations: <none> Status: Running IP: 10.1.0.15 IPs: IP: 10.1.0.15 Containers: hello-busybox: Container ID: docker://dacd7d6f411764b02b26884ef48c5ceec1d60faace4a8fbbc670638e2a6cb806 Image: busybox:latest Image ID: docker-pullable://busybox@sha256:b5fc1d7b2e4ea86a06b0cf88de915a2c43a99a00b6b3c0af731e5f4c07ae8eff Port: <none> Host Port: <none> Command: sh Args: -c echo "hello, busybox!"; sleep 300; State: Running Ready: True Restart Count: 0 Environment: <none> Mounts: /var/run/secrets/kubernetes.io/serviceaccount from default-token-qvt58 (ro) Conditions: Type Status Initialized True Ready True ContainersReady True PodScheduled True Volumes: default-token-qvt58: Type: Secret (a volume populated by a Secret) SecretName: default-token-qvt58 Optional: false QoS Class: BestEffort Node-Selectors: <none> Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s node.kubernetes.io/unreachable:NoExecute op=Exists for 300s Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 3m13s default-scheduler Successfully assigned default/hello-busybox to docker-desktop Normal Pulling 3m12s kubelet Pulling image "busybox:latest" Normal Pulled 3m12s kubelet Successfully pulled image "busybox:latest" in 448.2757ms Normal Created 3m12s kubelet Created container hello-busybox Normal Started 3m12s kubelet Started container hello-busybox
apiVersion: v1 kind: Pod metadata: name: hello-busybox-resources spec: containers: - name: hello-busybox-resources image: busybox:latest command: ['sh', '-c', 'echo "hello, busybox!"; sleep 300;'] resources: requests: memory: 100Mi cpu: 100m limits: memory: 200Mi cpu: 200mYou can define a "ResourceQuota" to set the maximum resources (requests and limits) for all the objects to be created within a namespace.
$ vi namespace-resource-quota.yaml
apiVersion: v1 kind: ResourceQuota metadata: name: namespace-resource-quota spec: hard: requests.memory: 1Gi requests.cpu: 1 limits.memory: 2Gi limits.cpu: 2If you try to create an object that doesn't define a requests or limits, you will get an error:
Error from server (Forbidden): error when creating "hello-busybox-pod.yaml": pods "hello-busybox" is forbidden: failed quota: namespace-resource-quota: must specify limits.cpu for: hello-busybox; limits.memory for: hello-busybox; requests.cpu for: hello-busybox; requests.memory for: hello-busyboxTo check the resources usage:
$ kubectl get resourcequota/namespace-resource-quota
NAME AGE REQUEST LIMIT namespace-resource-quota 13m requests.cpu: 100m/1, requests.memory: 100Mi/1Gi limits.cpu: 200m/2, limits.memory: 200Mi/2GiYou can also define a "LimitRange" to set the maximum resources (requests and limits) for all the objects of a specific type.
$ vi resources-limit-range.yaml
apiVersion: v1 kind: LimitRange metadata: name: resources-limit-range spec: limits: - default: # default value for containers that doesn't specifyc a request or limits cpu: 1024m defaultRequest: cpu: 512m min: # minimum value for request and limits cpu: 512m max: # maximum value for request and limits cpu: "2" type: ContainerYou will get an error, if you try to create an object that define values for requests or limits that exceeds the values in the ResourceQuota or LimitRange.
Error from server (Forbidden): error when creating "hello-busybox-resources-pod.yaml": pods "hello-busybox-resources" is forbidden: minimum cpu usage per Container is 512m, but request is 100m
$ vi hello-init-container-busybox-pod.yaml
apiVersion: v1 kind: Pod metadata: name: hello-init-container-busybox spec: initContainers: - name: init-container-show-hello image: busybox:latest command: ['sh', '-c', 'echo "hello, init container!"; sleep 5;'] containers: - name: hello-init-container-busybox image: busybox:latest command: ['sh', '-c', 'echo "hello, busybox!"; sleep 300;']
$ kubectl get pods hello-init-container-busybox
NAME READY STATUS RESTARTS AGE hello-init-container-busybox 1/1 Running 3 (2m48s ago) 18mNote that the column READY is showing "1/1" which means that the Pod has only 1 container and it's running.
$ kubectl logs hello-init-container-busybox -c init-container-show-hello
hello, init container!
$ vi hello-sidcar-container-busybox-pod.yaml
apiVersion: v1 kind: Pod metadata: name: hello-sidcar-container-busybox spec: initContainers: - name: sidcar-container-show-hello image: busybox:latest command: ['sh', '-c', 'echo "hello, sidcar container!"; sleep infinity;'] restartPolicy: Always containers: - name: hello-sidcar-container-busybox image: busybox:latest command: ['sh', '-c', 'echo "hello, busybox!"; sleep 300;']
$ kubectl get pods hello-sidcar-container-busybox
NAME READY STATUS RESTARTS AGE hello-sidcar-container-busybox 2/2 Running 0 75sNote that the column READY is showing "2/2" which means that two containers are running.
$ kubectl logs hello-sidcar-container-busybox -c sidcar-container-show-hello
hello, sidcar container!
exec: command: ['sh', '-c', 'test -f /tmp/file1;']
tcpSocket: port: 5432
httpGet: path: /healthz port: 80
grpc: port: 1024
$ vi hello-probes-busybox-pod.yaml
apiVersion: v1 kind: Pod metadata: name: hello-probes-busybox spec: restartPolicy: Always containers: - name: hello-probes-busybox image: busybox:latest command: ['sh', '-c', 'touch /tmp/liveness-probe; touch /tmp/readiness-probe; touch /tmp/startup-probe; sleep infinity;'] startupProbe: exec: command: - cat - /tmp/liveness-probe initialDelaySeconds: 5 timeoutSeconds: 5 periodSeconds: 10 failureThreshold: 5 successThreshold: 1 terminationGracePeriodSeconds: 5 livenessProbe: exec: command: - cat - /tmp/readiness-probe initialDelaySeconds: 5 timeoutSeconds: 5 periodSeconds: 10 failureThreshold: 5 successThreshold: 1 terminationGracePeriodSeconds: 5 readinessProbe: exec: command: - cat - /tmp/startup-probe initialDelaySeconds: 5 timeoutSeconds: 5 periodSeconds: 10 failureThreshold: 5 successThreshold: 5Let's create the Pod:
$ kubectl apply -f hello-probes-busybox-pod.yaml
pod/hello-probes-busybox createdLet's check the Pod:
$ kubectl get pods -w
NAME READY STATUS RESTARTS AGE hello-probes-busybox 0/1 Running 0 3s hello-probes-busybox 0/1 Running 0 10s hello-probes-busybox 1/1 Running 0 41s
$ vi hello-labels-busybox-pod.yaml
apiVersion: v1 kind: Pod metadata: name: hello-labels-busybox # will be used as the hostname of the conatiners labels: label1-key/label1-name: label1-value spec: containers: - name: hello-labels-busybox image: busybox:latest command: ['sh', '-c', 'echo "hello, busybox!"; sleep infinity;']Let's deploy the hello-labels-busybox-pod.yaml file:
$ kubectl apply -f hello-labels-busybox-pod.yaml
pod/hello-labels-busybox createdTo add, update, or delete a label, you can update and apply the manifest file of the Pod. You can also use the imperative command kubectl label to add, update, or delete labels.
$ kubectl label pods hello-labels-busybox "label2-key/label2-name=label2-value"
pod/hello-labels-busybox labeledTo show the labels attached to the Pod:
$ kubectl get pods hello-labels-busybox --show-labels
NAME READY STATUS RESTARTS AGE LABELS hello-labels-busybox 1/1 Running 0 109s label1-key/label1-name=label1-value,label2-key/label2-name=label2-valueYou can use the option "--label-columns" ("-L") to present the label names as columns in the output of the command.
$ kubectl get pods hello-labels-busybox -L label1-key/label1-name -L LABEL-UNKNOWN
NAME READY STATUS RESTARTS AGE LABEL1-NAME LABEL-UNKNOWN hello-labels-busybox 1/1 Running 0 2m label1-valueTo update a label of a pod:
$ kubectl label pods hello-labels-busybox "label1-key/label1-name=label1-value-new" --overwrite
pod/hello-labels-busybox labeledYou need to use the option "--overwrite", otherwise you will get an error:
$ kubectl label pods hello-labels-busybox "label2-key/label2-name-"
pod/hello-labels-busybox labeledTo show the labels changes:
$ kubectl get pods hello-labels-busybox --show-labels
NAME READY STATUS RESTARTS AGE LABELS hello-labels-busybox 1/1 Running 0 3m label1-key/label1-name=label1-value-newYou can use the option "--selector" ("-l") to filter Pods based on their label names.
$ kubectl get pods -l "label1-key/label1-name=label1-value-new" --show-labels
NAME READY STATUS RESTARTS AGE LABELS hello-labels-busybox 1/1 Running 0 3m label1-key/label1-name=label1-value-newExample using the "!" operator.
$ kubectl get pods -l '!label2-key/label2-name' --show-labels
NAME READY STATUS RESTARTS AGE LABELS hello-labels-busybox 1/1 Running 0 3m label1-key/label1-name=label1-value-new
$ kubectl delete -f hello-busybox-pod.yaml
pod "hello-busybox" deletedTo delete a Pod using its name:
$ kubectl delete pod hello-busybox
pod "hello-busybox" deletedBy default, the Pod takes 30 seconds to gracefully shut down before it get completely terminated. Meanwhile the pod will show the state "Terminating".
$ kubectl delete pod hello-busybox --grace-period=0
pod "hello-busybox" deleted