Anasayfa / Software / Mastering Kubernetes: Advanced Guide to Orchestrating Containers

Mastering Kubernetes: Advanced Guide to Orchestrating Containers

Kubernetes cluster

Orchestrating containers at scale is the cornerstone of modern cloud‑native architectures, and Kubernetes has become the de‑facto platform for that job. This guide assumes you already know Docker basics and are comfortable with Linux command‑line tools. We’ll walk through building a production‑ready multi‑node cluster, wiring up networking, deploying a real‑world app, and hardening security—all with concrete commands you can copy‑paste.

What You’ll Need

  • At least three Linux VMs (Ubuntu 22.04 LTS recommended) – one master and two workers.
  • Root or sudo access on each node.
  • Minimum 2 CPU and 4 GB RAM per node.
  • Static IPs or a DHCP reservation for each VM.
  • kubectl installed locally (or on the master).

Step 1: Set Up a Multi‑Node Cluster

We’ll use kubeadm because it gives you full control over each component. Begin by disabling swap on every node (Kubernetes won’t start otherwise):
sudo swapoff -a && sudo sed -i '/ swap / s/^/#/' /etc/fstab
Next, install the required packages:

sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release
curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo gpg --dearmor -o /usr/share/keyrings/kubernetes-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

On the master, initialise the control plane (replace --apiserver-advertise-address with your master’s IP):

sudo kubeadm init --apiserver-advertise-address=192.168.1.10 --pod-network-cidr=192.168.0.0/16

After a successful init, set up your local kubeconfig:

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

Now join each worker node using the token printed at the end of kubeadm init. If you missed it, generate a new one:

sudo kubeadm token create --print-join-command

Run the resulting kubeadm join command on each worker. Verify the cluster is healthy:

kubectl get nodes

You should see all three nodes in a Ready state.

Step 2: Install a Container Runtime

Kubernetes 1.24+ dropped Docker as a supported runtime, so we’ll use containerd. Install it on every node:

sudo apt-get install -y containerd
sudo systemctl enable --now containerd

Configure the default runtime class (optional but recommended for consistency):

cat <<EOF | sudo tee /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
  runtime_type = "io.containerd.runc.v2"
EOF
sudo systemctl restart containerd

After restarting, confirm Docker‑style commands still work:

sudo crictl info

If you see JSON output, you’re good to go.

Step 3: Deploy a Sample Application

Let’s spin up a classic nginx deployment with a Service and an Ingress. First, create a namespace to keep things tidy:

kubectl create namespace demo

Now apply the manifest:

cat <<'EOF' | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
  namespace: demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.25-alpine
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  namespace: demo
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
  namespace: demo
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: nginx.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-svc
            port:
              number: 80
EOF

Check that pods are running:

kubectl get pods -n demo -o wide

Because we haven’t installed an Ingress controller yet, the Ingress resource will stay pending. We’ll fix that in the next step.

Step 4: Configure Networking with Calico

While the --pod-network-cidr=192.168.0.0/16 flag prepared the CIDR, we still need a CNI plugin. Calico is a popular choice for its network policy capabilities. Install it on the master (it propagates to workers):

kubectl apply -f https://projectcalico.docs.tigera.io/manifests/calico.yaml

Wait for all Calico pods to become Running:

kubectl get pods -n kube-system -l k8s-app=calico-node

Now install an NGINX Ingress controller (also a Calico‑compatible deployment):

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yaml

After the controller is ready, add an entry to your local /etc/hosts (or DNS) so nginx.local resolves to the Ingress IP:

# Get external IP (or use the node IP for minikube)
kubectl get svc -n ingress-nginx ingress-nginx-controller
# Example entry
echo "192.168.1.10 nginx.local" | sudo tee -a /etc/hosts

Now you can curl the service:

curl http://nginx.local

You should see the default NGINX welcome page, confirming that networking, Service, and Ingress are all wired correctly.

Step 5: Implement Autoscaling

Kubernetes offers two autoscaling mechanisms: the Horizontal Pod Autoscaler (HPA) for workloads and the Cluster Autoscaler for node pools. First, enable the metrics server (required for HPA):

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

Verify it’s serving metrics:

kubectl top nodes

Now create an HPA that scales the NGINX deployment based on CPU usage:

kubectl autoscale deployment nginx-deploy 
  --cpu-percent=50 --min=2 --max=6 -n demo

Generate load to see it in action (run from any machine that can reach the Ingress):

while true; do curl -s http://nginx.local > /dev/null; done

In another terminal, watch the HPA:

kubectl get hpa -n demo

When CPU crosses 50 %, the replica count will rise up to six. For node‑level autoscaling, install the Cluster Autoscaler (the exact manifest varies by cloud provider; for bare‑metal you can use the open‑source version with custom node‑group definitions).

Step 6: Secure the Cluster with RBAC

Role‑Based Access Control (RBAC) is the default security model, but you still need to create least‑privilege roles for developers and CI pipelines. Let’s create a read‑only role for the demo namespace:

cat <<'EOF' | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: demo
  name: demo-viewer
rules:
- apiGroups: ["", "apps", "extensions"]
  resources: ["pods", "deployments", "services", "ingresses"]
  verbs: ["get", "list", "watch"]
EOF

# Bind the role to a user (replace USERNAME with your IdP user)
cat <<'EOF' | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: demo-viewer-binding
  namespace: demo
subjects:
- kind: User
  name: alice@example.com
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: demo-viewer
  apiGroup: rbac.authorization.k8s.io
EOF

Test the restriction by impersonating the user:

kubectl auth can-i create deployments -n demo --as=alice@example.com

The command should return no, confirming the role is correctly scoped.

Common Mistakes to Avoid

1. Skipping swap disable. Even a tiny swap file will cause kubelet to refuse to start.
2. Mismatched pod CIDR and CNI config. If the CIDR you pass to kubeadm init doesn’t match Calico’s clusterCIDR, pods won’t get IPs.
3. Using Docker as the runtime on newer clusters. Kubernetes 1.24+ expects a CRI‑compatible runtime like containerd.
4. Forgetting to open required ports. Ports 6443, 10250, 30000‑32767 (NodePort) and the CNI overlay ports must be reachable between nodes.
5. Applying manifests without namespace isolation. Deploying everything into default makes cleanup messy and can cause naming collisions.
6. Neglecting metrics‑server. HPA will silently stay at the minimum replica count if metrics aren’t available.

Tips and Tricks

• Use kubeadm reset on a node before re‑joining it to avoid “node already exists” errors.
• Store your kubeconfig in a version‑controlled .kube directory with separate contexts for each cluster.
• Leverage kubectl kustomize to templatize environment‑specific values (dev, staging, prod).
• Enable audit logging on the API server for compliance: add --audit-log-path=/var/log/kubernetes/audit.log to the API server manifest.
• When using Calico network policies, start with a “default deny all” policy and then whitelist required traffic to reduce blast‑radius of compromised pods.

Frequently Asked Questions

Can I run Kubernetes on a single VM for testing?

Yes. Tools like kind (Kubernetes IN Docker) or minikube spin up a single‑node cluster quickly, but they hide many production‑level steps such as CNI installation and RBAC configuration.

Do I need a separate load balancer for the Ingress controller?

On bare‑metal you can expose the NGINX Ingress controller via a NodePort or HostPort. For cloud deployments, attach a cloud‑provider LB (AWS ELB, GCP LB) to the Ingress Service of type LoadBalancer for high‑availability.

How often should I upgrade my cluster?

Kubernetes releases a new minor version roughly every three months. Aim to upgrade at least once per quarter to stay on supported versions, benefit from security patches, and avoid painful version gaps.

Conclusion

By following this guide you’ve built a robust, production‑grade Kubernetes cluster, wired up networking, deployed a real application, and layered in autoscaling and security. The real power of Kubernetes shines when you start integrating CI/CD pipelines, service meshes, and observability stacks. Keep experimenting, automate the repetitive parts with Terraform or Ansible, and remember that the best way to master orchestration is to keep breaking and fixing things in a sandbox before you ship to production.

Photo by Growtika on Unsplash

Etiketlendi: