Skip to main content

Command Palette

Search for a command to run...

Terminal

Updated
7 min readView as Markdown

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:

  1. Use a local tag (e.g., image: go-k8s-app:local).

  2. Set imagePullPolicy: Never (or IfNotPresent). 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