Learn how to deploy and manage Podman containers using Kubernetes YAML manifests with kubectl integration. This tutorial covers systemd user services, YAML generation, pod networking, and volume management.
Prerequisites
- Basic Linux command line knowledge
- Understanding of containers and containerization concepts
- Familiarity with YAML syntax
What this solves
Podman provides Kubernetes-compatible container orchestration without requiring a full Kubernetes cluster. This approach lets you use familiar kubectl commands and Kubernetes YAML manifests to manage containers locally while maintaining the security benefits of rootless containers.
You get the declarative configuration model of Kubernetes with the simplicity and security of Podman, making it ideal for development environments, edge deployments, or single-node production setups that don't need the complexity of a full Kubernetes cluster.
Step-by-step configuration
Update system packages
Start by updating your package manager to ensure you get the latest container tools.
sudo apt update && sudo apt upgrade -y
Install Podman and kubectl
Install Podman for container management and kubectl for Kubernetes-style commands.
sudo apt install -y podman curl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
Configure systemd user services
Enable lingering for your user to allow systemd user services to run without being logged in.
sudo loginctl enable-linger $USER
systemctl --user enable podman.socket
systemctl --user start podman.socket
Set up Podman systemd integration
Configure Podman to work with systemd for automatic container management and service integration.
mkdir -p ~/.config/systemd/user
echo 'export DOCKER_HOST=unix:///run/user/'$UID'/podman/podman.sock' >> ~/.bashrc
source ~/.bashrc
Create a sample application
Set up a simple web application to demonstrate Kubernetes YAML deployment with Podman.
mkdir -p ~/podman-k8s-demo
cd ~/podman-k8s-demo
Create Kubernetes deployment YAML
Define a Kubernetes deployment manifest for a sample NGINX application with proper resource limits and labels.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: docker.io/nginx:latest
ports:
- containerPort: 80
resources:
limits:
memory: "256Mi"
cpu: "500m"
requests:
memory: "128Mi"
cpu: "250m"
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
volumes:
- name: nginx-config
configMap:
name: nginx-config
Create Kubernetes service YAML
Define a service to expose the NGINX deployment with proper port mapping and service discovery.
apiVersion: v1
kind: Service
metadata:
name: nginx-service
labels:
app: nginx
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30080
type: NodePort
Create ConfigMap for custom configuration
Set up a ConfigMap to demonstrate volume mounting and configuration management.
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
data:
nginx.conf: |
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}
Generate Podman containers from Kubernetes YAML
Use Podman to create containers directly from Kubernetes manifests without a cluster.
podman play kube nginx-configmap.yaml
podman play kube nginx-deployment.yaml
podman play kube nginx-service.yaml
Create systemd services from Kubernetes YAML
Generate systemd service files for automatic startup and management of your Kubernetes workloads.
podman generate systemd --new --files --name nginx-deployment-nginx
mv *.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable pod-nginx-deployment.service
systemctl --user start pod-nginx-deployment.service
Set up kubectl integration with Podman
Configure kubectl to work with Podman by creating a kubeconfig that points to Podman's API.
mkdir -p ~/.kube
cat > ~/.kube/config << EOF
apiVersion: v1
kind: Config
clusters:
- cluster:
server: unix:///run/user/$UID/podman/podman.sock
name: podman
contexts:
- context:
cluster: podman
user: podman
name: podman
current-context: podman
users:
- name: podman
EOF
Configure pod networking
Set up pod networking to allow communication between containers and expose services properly.
podman network create --driver bridge podman-k8s
echo 'podman-k8s network created for Kubernetes-style networking'
Create persistent volume configuration
Set up persistent volumes for stateful applications that need data persistence.
apiVersion: v1
kind: PersistentVolume
metadata:
name: local-storage
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/tmp/data"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: local-claim
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
Deploy application with persistent storage
Create the storage directory and deploy the persistent volume configuration.
sudo mkdir -p /tmp/data
sudo chown $USER:$USER /tmp/data
chmod 755 /tmp/data
podman play kube persistent-volume.yaml
Verify your setup
Test that your Podman Kubernetes integration is working correctly.
podman pod list
podman ps -a
systemctl --user status pod-nginx-deployment.service
curl http://localhost:30080
podman logs nginx-deployment-nginx
You can also use kubectl-style commands if you have the integration configured:
podman version
podman info | grep -A5 "network"
podman network ls
Managing your deployment
Update deployment with new YAML
Modify your YAML files and redeploy to update your running containers.
podman play kube --replace nginx-deployment.yaml
systemctl --user restart pod-nginx-deployment.service
Scale your deployment
Modify the replicas field in your deployment YAML and redeploy to scale containers.
sed -i 's/replicas: 2/replicas: 3/' nginx-deployment.yaml
podman play kube --replace nginx-deployment.yaml
Clean up deployment
Remove the deployment and associated resources when no longer needed.
systemctl --user stop pod-nginx-deployment.service
systemctl --user disable pod-nginx-deployment.service
podman play kube --down nginx-deployment.yaml
podman play kube --down nginx-service.yaml
podman play kube --down nginx-configmap.yaml
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| kubectl commands fail | Podman socket not running | systemctl --user start podman.socket |
| Containers exit immediately | Resource limits too restrictive | Increase memory/CPU limits in YAML |
| Service not accessible | Port mapping incorrect | Check podman port output and service YAML |
| Volume mount permission denied | Incorrect directory ownership | chown $USER:$USER /path/to/volume and chmod 755 |
| Systemd service fails to start | Pod definition changed | Regenerate service files with podman generate systemd |
| Network connectivity issues | Container network misconfigured | Recreate with podman network create |
Next steps
- Configure nginx reverse proxy for Podman containers with SSL and load balancing for production traffic management
- Secure Podman containers with SELinux and AppArmor mandatory access controls for enhanced security
- Set up Podman container monitoring with Prometheus and Grafana for observability
- Configure private container registry with Harbor and SSL for secure image storage
Running this in production?
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Global variables
SCRIPT_NAME=$(basename "$0")
INSTALL_USER=""
DEMO_DIR=""
# Usage message
usage() {
echo "Usage: $SCRIPT_NAME [OPTIONS]"
echo "Deploy Podman containers with Kubernetes YAML manifests and kubectl integration"
echo ""
echo "OPTIONS:"
echo " -u, --user USERNAME Install for specific user (default: current user)"
echo " -d, --demo-dir PATH Demo directory path (default: ~/podman-k8s-demo)"
echo " -h, --help Show this help message"
echo ""
echo "Example: $SCRIPT_NAME --user myuser --demo-dir /home/myuser/k8s-demo"
}
# Logging functions
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Cleanup function
cleanup() {
if [[ $? -ne 0 ]]; then
log_error "Installation failed. Cleaning up..."
# Remove demo directory if created
if [[ -n "${DEMO_DIR}" && -d "${DEMO_DIR}" ]]; then
rm -rf "${DEMO_DIR}" 2>/dev/null || true
fi
fi
}
# Set trap for cleanup
trap cleanup EXIT
# Parse command line arguments
parse_args() {
INSTALL_USER="${USER:-$(whoami)}"
DEMO_DIR=""
while [[ $# -gt 0 ]]; do
case $1 in
-u|--user)
INSTALL_USER="$2"
shift 2
;;
-d|--demo-dir)
DEMO_DIR="$2"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
log_error "Unknown option: $1"
usage
exit 1
;;
esac
done
# Set default demo directory if not provided
if [[ -z "${DEMO_DIR}" ]]; then
DEMO_DIR="/home/${INSTALL_USER}/podman-k8s-demo"
if [[ "${INSTALL_USER}" == "root" ]]; then
DEMO_DIR="/root/podman-k8s-demo"
fi
fi
}
# Check prerequisites
check_prerequisites() {
echo "[1/10] Checking prerequisites..."
if [[ $EUID -ne 0 ]]; then
log_error "This script must be run as root"
exit 1
fi
# Verify target user exists
if ! id "${INSTALL_USER}" >/dev/null 2>&1; then
log_error "User ${INSTALL_USER} does not exist"
exit 1
fi
# Check for required commands
command -v curl >/dev/null 2>&1 || { log_error "curl is required but not installed"; exit 1; }
log_success "Prerequisites check completed"
}
# Detect distribution
detect_distro() {
echo "[2/10] Detecting distribution..."
if [[ ! -f /etc/os-release ]]; then
log_error "Cannot detect distribution - /etc/os-release not found"
exit 1
fi
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update"
PKG_INSTALL="apt install -y"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum update -y"
PKG_INSTALL="yum install -y"
;;
*)
log_error "Unsupported distribution: $ID"
exit 1
;;
esac
log_success "Detected distribution: $ID (using $PKG_MGR)"
}
# Update system packages
update_system() {
echo "[3/10] Updating system packages..."
$PKG_UPDATE
log_success "System packages updated"
}
# Install Podman and dependencies
install_podman() {
echo "[4/10] Installing Podman and dependencies..."
$PKG_INSTALL podman curl
log_success "Podman and dependencies installed"
}
# Install kubectl
install_kubectl() {
echo "[5/10] Installing kubectl..."
local kubectl_version
kubectl_version=$(curl -L -s https://dl.k8s.io/release/stable.txt)
curl -LO "https://dl.k8s.io/release/${kubectl_version}/bin/linux/amd64/kubectl"
install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
rm -f kubectl
log_success "kubectl installed"
}
# Configure systemd user services
configure_systemd() {
echo "[6/10] Configuring systemd user services..."
# Enable lingering for user
loginctl enable-linger "${INSTALL_USER}"
# Configure as the target user
sudo -u "${INSTALL_USER}" bash -c "
systemctl --user enable podman.socket
systemctl --user start podman.socket
"
log_success "Systemd user services configured"
}
# Set up Podman integration
setup_podman_integration() {
echo "[7/10] Setting up Podman systemd integration..."
local user_home
user_home=$(eval echo "~${INSTALL_USER}")
local user_uid
user_uid=$(id -u "${INSTALL_USER}")
# Create user config directory
sudo -u "${INSTALL_USER}" mkdir -p "${user_home}/.config/systemd/user"
# Add DOCKER_HOST to bashrc if not already present
if ! sudo -u "${INSTALL_USER}" grep -q "DOCKER_HOST.*podman.sock" "${user_home}/.bashrc" 2>/dev/null; then
sudo -u "${INSTALL_USER}" bash -c "echo 'export DOCKER_HOST=unix:///run/user/${user_uid}/podman/podman.sock' >> ${user_home}/.bashrc"
fi
log_success "Podman integration configured"
}
# Create demo application
create_demo_app() {
echo "[8/10] Creating demo application..."
# Create demo directory
sudo -u "${INSTALL_USER}" mkdir -p "${DEMO_DIR}"
# Create ConfigMap YAML
sudo -u "${INSTALL_USER}" cat > "${DEMO_DIR}/configmap.yaml" << 'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
data:
nginx.conf: |
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
}
EOF
# Create Deployment YAML
sudo -u "${INSTALL_USER}" cat > "${DEMO_DIR}/deployment.yaml" << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: docker.io/nginx:latest
ports:
- containerPort: 80
resources:
limits:
memory: "256Mi"
cpu: "500m"
requests:
memory: "128Mi"
cpu: "250m"
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
volumes:
- name: nginx-config
configMap:
name: nginx-config
EOF
# Create Service YAML
sudo -u "${INSTALL_USER}" cat > "${DEMO_DIR}/service.yaml" << 'EOF'
apiVersion: v1
kind: Service
metadata:
name: nginx-service
labels:
app: nginx
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30080
type: NodePort
EOF
# Set proper permissions
chown -R "${INSTALL_USER}:${INSTALL_USER}" "${DEMO_DIR}"
chmod 755 "${DEMO_DIR}"
chmod 644 "${DEMO_DIR}"/*.yaml
log_success "Demo application files created in ${DEMO_DIR}"
}
# Create helper scripts
create_helper_scripts() {
echo "[9/10] Creating helper scripts..."
# Create deployment script
sudo -u "${INSTALL_USER}" cat > "${DEMO_DIR}/deploy.sh" << 'EOF'
#!/bin/bash
set -e
echo "Deploying Podman Kubernetes demo..."
# Source environment
source ~/.bashrc
# Apply manifests using podman kube play
podman kube play configmap.yaml
podman kube play deployment.yaml
podman kube play service.yaml
echo "Deployment complete!"
echo "Check status with: podman pod ps"
echo "Check containers with: podman ps"
EOF
# Create cleanup script
sudo -u "${INSTALL_USER}" cat > "${DEMO_DIR}/cleanup.sh" << 'EOF'
#!/bin/bash
set -e
echo "Cleaning up Podman Kubernetes demo..."
# Remove deployments
podman kube down deployment.yaml 2>/dev/null || true
podman kube down service.yaml 2>/dev/null || true
podman kube down configmap.yaml 2>/dev/null || true
# Clean up any remaining containers/pods
podman pod rm -f nginx-deployment 2>/dev/null || true
podman container prune -f 2>/dev/null || true
echo "Cleanup complete!"
EOF
# Set execute permissions
chmod 755 "${DEMO_DIR}/deploy.sh" "${DEMO_DIR}/cleanup.sh"
chown "${INSTALL_USER}:${INSTALL_USER}" "${DEMO_DIR}/deploy.sh" "${DEMO_DIR}/cleanup.sh"
log_success "Helper scripts created"
}
# Verify installation
verify_installation() {
echo "[10/10] Verifying installation..."
# Check Podman
if podman --version >/dev/null 2>&1; then
log_success "Podman: $(podman --version)"
else
log_error "Podman installation failed"
exit 1
fi
# Check kubectl
if kubectl version --client >/dev/null 2>&1; then
log_success "kubectl: $(kubectl version --client --short 2>/dev/null || kubectl version --client)"
else
log_error "kubectl installation failed"
exit 1
fi
# Check systemd services
if sudo -u "${INSTALL_USER}" systemctl --user is-active podman.socket >/dev/null 2>&1; then
log_success "Podman socket service is active"
else
log_warning "Podman socket service is not active"
fi
log_success "Installation verification completed"
}
# Main function
main() {
parse_args "$@"
check_prerequisites
detect_distro
update_system
install_podman
install_kubectl
configure_systemd
setup_podman_integration
create_demo_app
create_helper_scripts
verify_installation
echo ""
log_success "Podman Kubernetes integration setup completed successfully!"
echo ""
echo "Demo files created in: ${DEMO_DIR}"
echo "To deploy the demo application:"
echo " 1. Switch to user: su - ${INSTALL_USER}"
echo " 2. Navigate to: cd ${DEMO_DIR}"
echo " 3. Run: ./deploy.sh"
echo " 4. Clean up: ./cleanup.sh"
echo ""
echo "Useful commands:"
echo " - podman pod ps"
echo " - podman ps"
echo " - podman kube play deployment.yaml"
echo " - podman kube down deployment.yaml"
}
# Run main function
main "$@"
Review the script before running. Execute with: bash install.sh