Back to HomeKubernetes

Kubernetes Tutorial: Step-by-Step K8s Practical Guide from Zero [2025 Update]

13 min min read
#Kubernetes#K8s#Tutorial#Beginner#Minikube#kubectl#Practical

Kubernetes Tutorial: Step-by-Step K8s Practical Guide from Zero [2025 Update]

Kubernetes Tutorial: Step-by-Step K8s Practical Guide from Zero [2025 Update]

After reading lots of Kubernetes concepts, it's time to get hands-on.

This tutorial will guide you step by step from scratch: installing the environment, deploying your first application, and learning basic commands.

No cloud account needed—you can complete this on your computer.

For Kubernetes basic concepts, please refer to Kubernetes Complete Guide first.


Environment Preparation

Before starting, you need to prepare a local Kubernetes environment.

Installing kubectl

kubectl is Kubernetes' command-line tool for communicating with clusters.

macOS:

# Using Homebrew
brew install kubectl

# Verify installation
kubectl version --client

Windows:

# Using Chocolatey
choco install kubernetes-cli

# Or using winget
winget install -e --id Kubernetes.kubectl

# Verify installation
kubectl version --client

Linux (Ubuntu/Debian):

# Download latest version
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"

# Install
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

# Verify installation
kubectl version --client

Local Cluster Options

Several tools can run Kubernetes locally:

ToolFeaturesBest For
MinikubeMost well-known, full-featuredBeginners' first choice
KindRuns K8s in DockerCI/CD, lightweight use
k3dDocker version of K3sResource-limited environments
Docker DesktopBuilt-in K8sMac/Windows users

This tutorial uses Minikube because it's best suited for learning.

Minikube Installation and Startup

Install Minikube:

# macOS
brew install minikube

# Windows
choco install minikube

# Linux
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube

Start Cluster:

# Start Minikube (defaults to Docker driver)
minikube start

# To specify resources
minikube start --cpus=4 --memory=8192

Verify Cluster Status:

# Check cluster status
minikube status

# Check nodes
kubectl get nodes

Output should look like this:

NAME       STATUS   ROLES           AGE   VERSION
minikube   Ready    control-plane   1m    v1.28.3

Common Minikube Commands:

CommandDescription
minikube startStart cluster
minikube stopStop cluster
minikube deleteDelete cluster
minikube dashboardOpen Web UI
minikube service <name>Open service in browser

Deploying Your First Application

Environment is ready. Let's deploy your first application.

Creating a Deployment

We'll use nginx as an example—this is the simplest way:

Method 1: Create with Command

kubectl create deployment nginx --image=nginx:1.25

What does this command do?

  • Creates a Deployment called nginx
  • Uses the nginx:1.25 image
  • Creates 1 Pod by default

Method 2: Create with YAML (Recommended)

Create file nginx-deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80

Apply the configuration:

kubectl apply -f nginx-deployment.yaml

Checking Pod Status

# View Pods
kubectl get pods

# View more information
kubectl get pods -o wide

# Watch status changes continuously
kubectl get pods -w

Output:

NAME                     READY   STATUS    RESTARTS   AGE
nginx-7854ff8877-x2vnz   1/1     Running   0          30s

Status Descriptions:

StatusDescription
PendingWaiting for scheduling or image download
ContainerCreatingCreating container
RunningRunning normally
ErrorError occurred
CrashLoopBackOffRepeated crash and restart

If status isn't Running, use this command to find out why:

kubectl describe pod <pod-name>

Creating a Service

Pod is running, but we can't access it yet. Need to create a Service.

Create with Command:

kubectl expose deployment nginx --port=80 --type=NodePort

Or with YAML:

Create file nginx-service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 80
    nodePort: 30080

Apply:

kubectl apply -f nginx-service.yaml

View Service:

kubectl get services

Output:

NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP        10m
nginx        NodePort    10.96.123.45    <none>        80:30080/TCP   10s

Accessing the Application

Access in Minikube:

# Method 1: Use minikube service
minikube service nginx

# Method 2: Get URL
minikube service nginx --url

This will automatically open your browser showing the nginx welcome page.

Congratulations! You've successfully deployed your first Kubernetes application.


💡 Having trouble learning K8s?

From concepts to implementation, we provide complete training and consulting services.

👉 Book a Free Consultation


Common kubectl Commands

kubectl is a tool you'll use every day. Here are the most commonly used commands.

Resource Viewing

Basic Viewing:

# View Pods
kubectl get pods

# View Deployments
kubectl get deployments

# View Services
kubectl get services

# View all resources
kubectl get all

# View specific namespace
kubectl get pods -n kube-system

Detailed Information:

# View Pod details
kubectl describe pod <pod-name>

# View Deployment details
kubectl describe deployment <deployment-name>

# Output as YAML format
kubectl get pod <pod-name> -o yaml

# Output as JSON format
kubectl get pod <pod-name> -o json

Custom Output Fields:

# Show only name and status
kubectl get pods -o custom-columns=NAME:.metadata.name,STATUS:.status.phase

# Filter by label
kubectl get pods -l app=nginx

Resource Creation and Management

Create Resources:

# Create from YAML
kubectl apply -f deployment.yaml

# Create all YAML files from directory
kubectl apply -f ./manifests/

# Create from URL
kubectl apply -f https://example.com/deployment.yaml

Modify Resources:

# Edit resource (opens editor)
kubectl edit deployment nginx

# Scale replicas
kubectl scale deployment nginx --replicas=3

# Update image
kubectl set image deployment/nginx nginx=nginx:1.26

Delete Resources:

# Delete single resource
kubectl delete pod <pod-name>

# Delete Deployment (will also delete Pods)
kubectl delete deployment nginx

# Delete from YAML
kubectl delete -f deployment.yaml

# Delete all Pods in specific namespace
kubectl delete pods --all -n <namespace>

Debugging Commands

These commands are very useful when problems occur:

View Logs:

# View Pod logs
kubectl logs <pod-name>

# Follow logs continuously
kubectl logs -f <pod-name>

# View previous container's logs (if restarted)
kubectl logs <pod-name> --previous

# Multi-container Pod specify container
kubectl logs <pod-name> -c <container-name>

Enter Container:

# Enter container and run shell
kubectl exec -it <pod-name> -- /bin/bash

# If no bash, use sh
kubectl exec -it <pod-name> -- /bin/sh

# Execute single command
kubectl exec <pod-name> -- ls /app

Port Forward:

# Forward Pod port to local
kubectl port-forward <pod-name> 8080:80

# Forward Service port to local
kubectl port-forward service/nginx 8080:80

Event Viewing:

# View all events
kubectl get events

# Sort by time
kubectl get events --sort-by='.lastTimestamp'

Advanced Tips

Set Aliases (Improve Efficiency):

# Add to .bashrc or .zshrc
alias k='kubectl'
alias kgp='kubectl get pods'
alias kgs='kubectl get services'
alias kgd='kubectl get deployments'
alias kd='kubectl describe'
alias kl='kubectl logs'

kubectl Auto-completion:

# Bash
source <(kubectl completion bash)

# Zsh
source <(kubectl completion zsh)

Context Management (Multi-cluster):

# View all contexts
kubectl config get-contexts

# Switch context
kubectl config use-context <context-name>

# View current context
kubectl config current-context

Writing YAML Files

Using YAML to manage Kubernetes resources is a best practice.

Basic Structure

Every Kubernetes YAML has four required fields:

apiVersion: v1          # API version
kind: Pod               # Resource type
metadata:               # Metadata
  name: my-pod
spec:                   # Specification (detailed resource settings)
  containers:
  - name: my-container
    image: nginx

Common apiVersion:

Resource TypeapiVersion
Pod, Service, ConfigMapv1
Deployment, ReplicaSetapps/v1
Ingressnetworking.k8s.io/v1
Job, CronJobbatch/v1

Common kind:

KindPurpose
PodSmallest deployment unit
DeploymentManage Pod lifecycle
ServiceNetwork access
ConfigMapConfiguration info
SecretSensitive info
IngressHTTP routing

Deployment YAML Detailed

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app                    # Deployment name
  labels:
    app: my-app                   # Deployment labels
spec:
  replicas: 3                     # Pod replica count
  selector:
    matchLabels:
      app: my-app                 # Selector, must match template labels
  template:                       # Pod template
    metadata:
      labels:
        app: my-app               # Pod labels
    spec:
      containers:
      - name: app                 # Container name
        image: my-app:1.0         # Image
        ports:
        - containerPort: 8080     # Container Port
        resources:                # Resource limits
          requests:
            memory: "128Mi"
            cpu: "250m"
          limits:
            memory: "256Mi"
            cpu: "500m"
        env:                      # Environment variables
        - name: NODE_ENV
          value: "production"
        livenessProbe:            # Liveness check
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10

Service YAML Detailed

apiVersion: v1
kind: Service
metadata:
  name: my-app-service
spec:
  type: ClusterIP                 # Type: ClusterIP, NodePort, LoadBalancer
  selector:
    app: my-app                   # Select Pods with this label
  ports:
  - name: http
    port: 80                      # Service Port
    targetPort: 8080              # Pod Port
    protocol: TCP

Common Errors

1. selector and labels mismatch

# Error: selector and template labels don't match
spec:
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-application  # Should be my-app

2. Indentation errors

# Error: YAML indentation incorrect
spec:
containers:    # Should be indented
- name: app

3. Missing required fields

# Error: Deployment missing selector
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
  # Missing selector
  template:
    ...

Validate YAML:

# Dry run, don't actually create
kubectl apply -f deployment.yaml --dry-run=client

# Validate syntax
kubectl apply -f deployment.yaml --validate=true

For more detailed explanations of objects, see Kubernetes Core Objects Tutorial.


🏗️ Need Kubernetes Architecture Design?

From development to production environment best practices, let experts help you plan.

👉 Book Architecture Consultation


Hands-on Practice: Deploying a Complete Application

Let's do a more complete exercise: deploying an application with frontend and backend.

Application Architecture

We'll deploy:

User → Frontend (React) → Backend (Node.js) → Database (PostgreSQL)

For simplicity, we'll use ready-made images.

Step-by-Step Tutorial

Step 1: Create Namespace

kubectl create namespace demo

Step 2: Deploy PostgreSQL

Create postgres.yaml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: postgres-config
  namespace: demo
data:
  POSTGRES_DB: myapp
  POSTGRES_USER: admin
---
apiVersion: v1
kind: Secret
metadata:
  name: postgres-secret
  namespace: demo
type: Opaque
data:
  POSTGRES_PASSWORD: cGFzc3dvcmQxMjM=  # password123 in base64
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: postgres
  namespace: demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
      - name: postgres
        image: postgres:15-alpine
        ports:
        - containerPort: 5432
        envFrom:
        - configMapRef:
            name: postgres-config
        - secretRef:
            name: postgres-secret
---
apiVersion: v1
kind: Service
metadata:
  name: postgres
  namespace: demo
spec:
  selector:
    app: postgres
  ports:
  - port: 5432
    targetPort: 5432

Apply:

kubectl apply -f postgres.yaml

Step 3: Deploy Backend

Create backend.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend
  namespace: demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: backend
  template:
    metadata:
      labels:
        app: backend
    spec:
      containers:
      - name: backend
        image: hashicorp/http-echo
        args:
        - "-text=Hello from Backend!"
        ports:
        - containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
  name: backend
  namespace: demo
spec:
  selector:
    app: backend
  ports:
  - port: 80
    targetPort: 5678

Apply:

kubectl apply -f backend.yaml

Step 4: Deploy Frontend

Create frontend.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
  namespace: demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
      - name: frontend
        image: nginx:1.25-alpine
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: frontend
  namespace: demo
spec:
  type: NodePort
  selector:
    app: frontend
  ports:
  - port: 80
    targetPort: 80
    nodePort: 30000

Apply:

kubectl apply -f frontend.yaml

Verify Results

Check All Resources:

kubectl get all -n demo

Output:

NAME                            READY   STATUS    RESTARTS   AGE
pod/backend-xxx                 1/1     Running   0          1m
pod/backend-yyy                 1/1     Running   0          1m
pod/frontend-xxx                1/1     Running   0          30s
pod/frontend-yyy                1/1     Running   0          30s
pod/postgres-xxx                1/1     Running   0          2m

NAME               TYPE        CLUSTER-IP       PORT(S)        AGE
service/backend    ClusterIP   10.96.xxx.xxx    80/TCP         1m
service/frontend   NodePort    10.96.xxx.xxx    80:30000/TCP   30s
service/postgres   ClusterIP   10.96.xxx.xxx    5432/TCP       2m

NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/backend    2/2     2            2           1m
deployment.apps/frontend   2/2     2            2           30s
deployment.apps/postgres   1/1     1            1           2m

Access Frontend:

minikube service frontend -n demo

Test Scaling:

# Scale backend to 5 replicas
kubectl scale deployment backend -n demo --replicas=5

# Check results
kubectl get pods -n demo -l app=backend

Cleanup:

kubectl delete namespace demo

FAQ: Common Questions

Q1: Pod Stuck in Pending?

Possible Causes:

CauseSolution
Insufficient resourcesIncrease Node resources or reduce requests
Can't pull imageCheck image name and network
PVC not boundCheck StorageClass and PV

Debug:

kubectl describe pod <pod-name>
# Look at Events section

Q2: Pod Stuck in CrashLoopBackOff?

Possible Causes:

  • Application startup failed
  • Configuration error
  • Dependent service not ready

Debug:

# View logs
kubectl logs <pod-name>

# View previous logs
kubectl logs <pod-name> --previous

Q3: Service Can't Reach Pod?

Checklist:

  1. Is Pod Running?
  2. Is Service selector correct?
  3. Is Port configuration correct?

Verify:

# Check Endpoints
kubectl get endpoints <service-name>

# If Endpoints is empty, selector doesn't match

Q4: How to Test Different K8s Versions Locally?

# Minikube can specify version
minikube start --kubernetes-version=v1.27.0

# Delete old cluster and rebuild
minikube delete
minikube start --kubernetes-version=v1.28.0

Q5: What's Next After Learning These?

GoalSuggestion
Deep learningLearn Ingress, PV/PVC, RBAC
ToolsLearn Helm, Kustomize
CloudTry EKS/GKE/AKS
CertificationPrepare for CKA/CKAD

Next Steps

After completing this tutorial, you can:

GoalAction
Choose cloud serviceRead Kubernetes Cloud Services Comparison
Learn more toolsRead Kubernetes Tools Ecosystem Guide
Deep dive into objectsRead Kubernetes Core Objects Tutorial
Prepare for certificationRead Kubernetes Certification Guide

🚀 Ready to Use Kubernetes in Production?

From local development to production deployment, CloudInsight helps your team transition smoothly.

👉 Book a Consultation Now


Further Reading


References

Need Professional Cloud Advice?

Whether you're evaluating cloud platforms, optimizing existing architecture, or looking for cost-saving solutions, we can help

Book Free Consultation

Related Articles