Terminal
Basic Podman Commands
Containers
List running containers
podman ps
List all containers
podman ps -a
Start container
podman start <container>
Stop container
podman stop <container>
Restart container
podman restart <container>
Delete container
podman rm <container>
Delete forcefully
podman rm -f <container>
Images
List images
podman images
Pull image
podman pull postgres:16
Build image
podman build -t myapp .
Remove image
podman rmi <image>
Logs & Debugging
View logs
podman logs <container>
Follow logs
podman logs -f <container>
Inspect container
podman inspect <container>
Container resource usage
podman stats
Shell Access
Open shell inside container
podman exec -it <container> bash
If bash isn't installed
podman exec -it <container> sh
Example
podman exec -it backend bash
Podman Compose
Start
podman compose up -d
Stop
podman compose stop
Start stopped services
podman compose start
Restart
podman compose restart
Rebuild
podman compose up -d --build
Destroy everything
podman compose down
Cleanup
Remove stopped containers
podman container prune
Remove unused images
podman image prune
Remove everything unused
podman system prune -a
Commands You'll Use Most Often During Development
podman compose up -d
podman ps
podman compose logs -f
podman exec -it <container> bash
podman compose restart
podman compose down
These six commands cover about 90% of day-to-day backend development with Podman Compose.
Issue 1: PostgreSQL Port Conflict (5433)
Error
rootlessport listen tcp4 0.0.0.0:5433:
bind: address already in use
Root Cause
The PostgreSQL container attempted to expose:
5433:5432
but port 5433 on the host machine was already occupied by another process.
Investigation Commands
Find which process owns the port
netstat -ano | findstr :5433
Get process details
tasklist /FI "PID eq <PID>"
Resolution
The port conflict was removed (either by stopping the existing process/container or freeing the port), allowing PostgreSQL to start successfully.
Issue 2: Redpanda/Kafka Port Conflict (9092)
Error
rootlessport listen tcp4 0.0.0.0:9092:
bind: address already in use
Root Cause
The Redpanda container attempted to expose:
9092:9092
but port 9092 was already occupied.
Investigation Commands
Check port ownership
netstat -ano | findstr :9092
Result
127.0.0.1:9092 LISTENING PID 16788
Find process
tasklist /FI "PID eq 16788"
Resolution
The port was eventually released. Later checks showed:
netstat -ano | findstr :9092
returned no results, meaning the port was no longer in use.
Issue 3: Podman Connection Failure
Error
Cannot connect to Podman
unable to connect to Podman socket:
dial tcp 127.0.0.1:52324
Initial Assumption
It appeared that:
Podman Machine was stopped
Podman socket was unavailable
Investigation
Check Podman
podman info
Check machine status
podman machine list
Check WSL status
wsl -l -v
Output
podman-machine-default Running
To troubleshoot further:
wsl --shutdown
Observation
There was a contradiction:
Machine = Running
Podman Socket = Unreachable
This suggested one of the following:
Stale socket
Podman service restart required
Temporary VM networking issue
Verification
Later, podman info returned successfully:
remoteSocket:
exists: true
and:
running: 0
stopped: 17
which confirmed:
✅ Podman VM running
✅ Podman API reachable
✅ Podman socket healthy
✅ No active containers
Kubernetes Locally Using WSL2, Ubuntu
In this setup, we created a local Kubernetes environment on a Windows machine using WSL2 (Windows Subsystem for Linux), Ubuntu, Docker, and Minikube. The goal was to build a clean development environment for learning and experimenting with Kubernetes.
Step 1: Verifying WSL2
We first checked whether WSL2 was installed:
wsl --status
This confirmed that WSL2 was already enabled and running.
Step 2: Installing Ubuntu on WSL2
We installed Ubuntu as our Linux environment:
wsl --install -d Ubuntu
This gave us a proper Linux-based development environment inside Windows.
Step 3: Basic Linux Verification
Once inside Ubuntu, we verified the system:
uname -a
pwd
ls -la
This ensured we were running inside a Linux kernel (WSL2).
Step 4: Installing Minikube
We downloaded and installed Minikube:
cd ~
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
Verification:
minikube version
Step 5: Installing Docker
Minikube requires a container runtime, so we installed Docker:
sudo apt update
sudo apt install -y docker.io
sudo service docker start
sudo usermod -aG docker $USER
After this, we restarted the shell and verified:
docker --version
Step 6: Starting Kubernetes Cluster
Finally, we started the local Kubernetes cluster using Docker as the driver:
minikube start --driver=docker
To verify the cluster:
kubectl get nodes
How to Build and Run Docker Images Locally in Kubernetes (Without Docker Hub)
When developing applications for Kubernetes locally, pushing images to a remote registry like Docker Hub for every single code change is a massive bottleneck. This guide walks through how we bypassed Docker Hub using Minikube and resolved a common WSL terminal syntax trap.
The Problem
By default, Kubernetes looks for images in public registries. If you build an image on your host machine and try to deploy it, Kubernetes throws an ErrImagePull or ImagePullBackOff error because it cannot find the image in the cloud.
To fix this, we need to inject our local Docker image directly into Minikube's internal cluster environment.
The Troubleshooting Journey & Fixes
1. Fixing the Bash Substitution Error
Our first attempt was to point our local terminal's Docker daemon to Minikube using command substitution. We ran into this error:
\( eval \){minikube docker-env}
-bash: ${minikube docker-env}: bad substitution
Why it happened: In Bash,
${...}is used for variable expansion, not executing commands.The Fix: Switch curly braces to parentheses
$(...)for proper command substitution:
eval $(minikube docker-env)
2. Bypassing WSL Context Issues (The Ultimate Fix)
Even after fixing the syntax, running docker ps showed we were still looking at the host machine's Docker daemon instead of Minikube's. This is a common quirk when using WSL (Windows Subsystem for Linux).
Instead of fighting the environment variables, we bypassed the eval command entirely by using Minikube’s dedicated build CLI. We just had to remember the trailing dot . to specify the build context (current directory):
minikube image build -t go-k8s-app:local .
This forces Minikube to grab the local directory, ship it to its internal cluster daemon, and build it natively inside Kubernetes.
Summary of Commands Used
| Command | Purpose |
|---|---|
minikube start |
Spins up the local Kubernetes cluster. |
minikube image build -t go-k8s-app:local . |
Builds the Docker image directly inside Minikube's environment (replaces docker build). |
minikube image ls |
Verifies that the image successfully exists inside the cluster cache. |
kubectl apply -f <file>.yaml |
Deploys the application manifests to the cluster. |
minikube service go-app-service |
Exposes and opens the application endpoint in your browser. |
Critical Rules for Local YAML Manifests
When deploying local images without a registry, you must update your Deployment YAML container spec with two things:
Use a local tag (e.g.,
image: go-k8s-app:local).Set
imagePullPolicy: Never(orIfNotPresent). This explicitly tells Kubernetes to stop looking on Docker Hub and pull it from the local Minikube cache instead.
spec:
containers:
- name: go-app
image: go-k8s-app:local
imagePullPolicy: Never # 👈 The secret sauce



