# Containers in VyOS - Podman Container Management

> Podman containers in VyOS - integration with VyOS networking, resource management, and configuration examples for Pi-hole, Zabbix, Prometheus, and Nginx

Source: https://opennix.org/en/docs/vyos/containers/


VyOS supports running Podman-based containers, allowing you to deploy applications directly on the router.

## Overview

VyOS uses **Podman** - a daemonless container engine compatible with Docker and the OCI standards.

**Capabilities**:
- Running OCI-compatible containers
- Integration with VyOS networking
- Managing images from various registries
- Custom container networks
- Volume and device mounting
- Resource limits (CPU, memory)
- Automatic restart
- Capability management

**Use cases**:
- Monitoring (Zabbix, Prometheus)
- DNS services (Pi-hole, AdGuard)
- Web services
- Proxy servers (Squid, HAProxy)
- VPN clients
- Utilities and tools

## Basic Configuration

### Simple Container

Running a container from Docker Hub:

```bash
set container name nginx image docker.io/nginx:latest
commit
```

The container starts automatically after commit.

### Container with a Port

Forward a host port into the container:

```bash
set container name nginx image docker.io/nginx:latest
set container name nginx port http source 8080
set container name nginx port http destination 80
set container name nginx port http protocol tcp
commit
```

Now nginx is available at `http://<vyos-ip>:8080`.

### Checking Status

```bash
show container
show container nginx
```

## Container Images

### Pulling an Image

The image is pulled automatically on commit, but you can also pull it manually:

```bash
add container image docker.io/nginx:latest
```

### Viewing Images

```bash
show container image
```

Example output:
```
REPOSITORY               TAG      IMAGE ID      CREATED      SIZE
docker.io/library/nginx  latest   3b25b682ea82  2 weeks ago  192 MB
```

### Updating an Image

```bash
update container image nginx
```

Pulls a new version of the image (if the tag has changed).

### Specifying an Image

```bash
set container name myapp image docker.io/myuser/myapp:1.0
commit
```

Format: `registry/repository:tag`

By default, Docker Hub (docker.io) is used.

### Entrypoint and Command

Overriding the entrypoint:

```bash
set container name myapp image myapp:latest
set container name myapp entrypoint '/usr/local/bin/custom-start.sh'
commit
```

Command arguments:

```bash
set container name myapp image myapp:latest
set container name myapp command '/bin/bash'
set container name myapp arguments '-c "echo Hello && sleep infinity"'
commit
```

## Network Configuration

### Container Network

Creating a custom network:

```bash
set container network mynet prefix 172.20.0.0/16
set container network mynet description 'Custom container network'
commit
```

IPv6:

```bash
set container network mynet prefix fd00::/64
commit
```

### Connecting a Container to a Network

```bash
set container name nginx network mynet
commit
```

The container receives a dynamic IP from the mynet network.

### Static IP

```bash
set container name nginx network mynet address 172.20.0.10
commit
```

### MTU for a Network

```bash
set container network mynet mtu 1400
commit
```

### VRF for a Container Network

```bash
set container network mynet vrf MGMT
commit
```

The container network will reside in the specified VRF.

### Viewing Networks

```bash
show container network
```

## Volumes and Mounting

### Mounting a Directory

```bash
set container name nginx volume config source /config/nginx
set container name nginx volume config destination /etc/nginx/conf.d
set container name nginx volume config mode ro
commit
```

- **source** - path on VyOS
- **destination** - path in the container
- **mode** - `ro` (read-only) or `rw` (read-write)

### Mounting a Configuration File

```bash
set container name app volume appconfig source /config/app.conf
set container name app volume appconfig destination /etc/app/app.conf
set container name app volume appconfig mode ro
commit
```

### Data in /config

To preserve data across reboots, use `/config`:

```bash
set container name database volume data source /config/database
set container name database volume data destination /var/lib/postgresql/data
set container name database volume data mode rw
commit
```

`/config` is the only VyOS directory that persists across reboots.

### Device Mounting

Mounting devices (for example, USB):

```bash
set container name app device source /dev/ttyUSB0
set container name app device destination /dev/ttyUSB0
commit
```

## Environment Variables

Passing environment variables into a container:

```bash
set container name myapp environment TZ value 'Europe/Moscow'
set container name myapp environment DEBUG value 'true'
set container name myapp environment DB_HOST value '192.168.1.100'
commit
```

Format:
```bash
set container name <name> environment <KEY> value '<value>'
```

Secrets (passwords):

```bash
set container name db environment POSTGRES_PASSWORD value 'secret123'
commit
```

## Ports

### TCP Port Forwarding

```bash
set container name webapp port http source 8080
set container name webapp port http destination 80
set container name webapp port http protocol tcp
commit
```

- **source** - port on VyOS
- **destination** - port in the container
- **protocol** - tcp or udp

Now traffic to `<vyos-ip>:8080` will be forwarded to the container on port 80.

### UDP Port Forwarding

```bash
set container name dnsserver port dns source 5353
set container name dnsserver port dns destination 53
set container name dnsserver port dns protocol udp
commit
```

### Multiple Ports

```bash
set container name webapp port http source 8080
set container name webapp port http destination 80
set container name webapp port http protocol tcp

set container name webapp port https source 8443
set container name webapp port https destination 443
set container name webapp port https protocol tcp

commit
```

### Binding to a Specific IP

To bind to a specific interface, use firewall DNAT:

```bash
set nat destination rule 10 destination address 192.168.1.1
set nat destination rule 10 destination port 8080
set nat destination rule 10 inbound-interface name eth1
set nat destination rule 10 translation address 172.20.0.10
set nat destination rule 10 translation port 80
set nat destination rule 10 protocol tcp
commit
```

## Hostname

Setting the container hostname:

```bash
set container name myapp host-name myapp.local
commit
```

The hostname is visible inside the container and in DNS (if configured).

## Restart Policy

Container restart policy on failure:

### Always

Always restart (default):

```bash
set container name myapp restart always
commit
```

### On-failure

Restart only on a non-zero exit code:

```bash
set container name myapp restart on-failure
commit
```

### No

Do not restart:

```bash
set container name myapp restart no
commit
```

## Resource Limits

### CPU Quota

CPU limit (as a percentage):

```bash
set container name myapp cpu-quota 50
commit
```

50 = 50% of one CPU core.

### Memory Limit

Memory limit (in megabytes):

```bash
set container name myapp memory 512
commit
```

The container is limited to 512 MB of RAM.

### Combined Limits

```bash
set container name myapp cpu-quota 25
set container name myapp memory 256
commit
```

## Capabilities

Managing Linux capabilities for a container.

### Adding a Capability

```bash
set container name myapp capability net-admin
set container name myapp capability sys-time
commit
```

Commonly used capabilities:
- **net-admin** - network management
- **sys-time** - changing the system time
- **net-raw** - raw sockets (ping)
- **sys-module** - loading kernel modules

### Privileged Containers

For full access (all capabilities):

```bash
set container name myapp capability all
commit
```

Use with caution (it reduces security).

## Sysctl Parameters

Changing kernel parameters for a container:

```bash
set container name myapp sysctl parameter net.ipv4.ip_forward value 1
commit
```

Requires the corresponding capabilities.

## Container Registries

### Configuring a Registry

By default, VyOS uses Docker Hub (docker.io).

Adding an additional registry:

```bash
set container registry gitlab address registry.gitlab.com
commit
```

### Authentication

For private registries:

```bash
set container registry myprivate address registry.example.com
set container registry myprivate authentication username myuser
set container registry myprivate authentication password mypassword
commit
```

### Insecure Registry

For an HTTP registry (not recommended):

```bash
set container registry myregistry address registry.local:5000
set container registry myregistry disable-verify
commit
```

### Mirror Registry

A Docker Hub mirror:

```bash
set container registry dockermirror mirror address mirror.gcr.io
commit
```

## Logging

### Logging Driver

By default, journald is used.

Changing the driver:

```bash
set container name myapp log-driver k8s-file
commit
```

Available drivers:
- **journald** - systemd journal
- **k8s-file** - Kubernetes-compatible files
- **none** - no logging

### Viewing Logs

```bash
show container log myapp
```

Logs are also available through journald:

```bash
journalctl -u vyos-container-myapp
```

## Configuration Examples

### Pi-hole DNS Server

Ad blocking and DNS filtering:

```bash
# Container network
set container network pihole prefix 172.21.0.0/24

# Pi-hole container
set container name pihole image docker.io/pihole/pihole:latest
set container name pihole network pihole address 172.21.0.10
set container name pihole restart always

# Ports
set container name pihole port dns-tcp source 5353
set container name pihole port dns-tcp destination 53
set container name pihole port dns-tcp protocol tcp

set container name pihole port dns-udp source 5353
set container name pihole port dns-udp destination 53
set container name pihole port dns-udp protocol udp

set container name pihole port web source 8080
set container name pihole port web destination 80
set container name pihole port web protocol tcp

# Environment
set container name pihole environment TZ value 'Europe/Moscow'
set container name pihole environment WEBPASSWORD value 'admin123'

# Volumes
set container name pihole volume config source /config/pihole/config
set container name pihole volume config destination /etc/pihole
set container name pihole volume config mode rw

set container name pihole volume dnsmasq source /config/pihole/dnsmasq.d
set container name pihole volume dnsmasq destination /etc/dnsmasq.d
set container name pihole volume dnsmasq mode rw

commit
```

Access the web interface at: `http://<vyos-ip>:8080/admin`

### Zabbix Monitoring

A multi-container monitoring system:

```bash
# Container network
set container network zabbix prefix 172.22.0.0/24

# PostgreSQL database
set container name postgres image docker.io/postgres:14
set container name postgres network zabbix address 172.22.0.2
set container name postgres restart always

set container name postgres environment POSTGRES_DB value 'zabbix'
set container name postgres environment POSTGRES_USER value 'zabbix'
set container name postgres environment POSTGRES_PASSWORD value 'zabbix_password'

set container name postgres volume data source /config/zabbix/postgresql
set container name postgres volume data destination /var/lib/postgresql/data
set container name postgres volume data mode rw

# Zabbix Server
set container name zabbix-server image docker.io/zabbix/zabbix-server-pgsql:latest
set container name zabbix-server network zabbix address 172.22.0.3
set container name zabbix-server restart always

set container name zabbix-server environment DB_SERVER_HOST value '172.22.0.2'
set container name zabbix-server environment POSTGRES_DB value 'zabbix'
set container name zabbix-server environment POSTGRES_USER value 'zabbix'
set container name zabbix-server environment POSTGRES_PASSWORD value 'zabbix_password'

set container name zabbix-server port trapper source 10051
set container name zabbix-server port trapper destination 10051
set container name zabbix-server port trapper protocol tcp

# Zabbix Web Frontend
set container name zabbix-web image docker.io/zabbix/zabbix-web-nginx-pgsql:latest
set container name zabbix-web network zabbix address 172.22.0.4
set container name zabbix-web restart always

set container name zabbix-web environment ZBX_SERVER_HOST value '172.22.0.3'
set container name zabbix-web environment DB_SERVER_HOST value '172.22.0.2'
set container name zabbix-web environment POSTGRES_DB value 'zabbix'
set container name zabbix-web environment POSTGRES_USER value 'zabbix'
set container name zabbix-web environment POSTGRES_PASSWORD value 'zabbix_password'
set container name zabbix-web environment PHP_TZ value 'Europe/Moscow'

set container name zabbix-web port http source 8081
set container name zabbix-web port http destination 8080
set container name zabbix-web port http protocol tcp

commit
```

Access: `http://<vyos-ip>:8081` (admin/zabbix)

### Nginx Web Server

A static web server with a custom configuration:

```bash
set container network web prefix 172.23.0.0/24

set container name nginx image docker.io/nginx:latest
set container name nginx network web address 172.23.0.10
set container name nginx restart always

set container name nginx port http source 8080
set container name nginx port http destination 80
set container name nginx port http protocol tcp

set container name nginx port https source 8443
set container name nginx port https destination 443
set container name nginx port https protocol tcp

# Volumes
set container name nginx volume html source /config/www/html
set container name nginx volume html destination /usr/share/nginx/html
set container name nginx volume html mode ro

set container name nginx volume config source /config/www/nginx.conf
set container name nginx volume config destination /etc/nginx/nginx.conf
set container name nginx volume config mode ro

commit
```

### Squid Proxy Server

An HTTP/HTTPS proxy:

```bash
set container network proxy prefix 172.24.0.0/24

set container name squid image docker.io/ubuntu/squid:latest
set container name squid network proxy address 172.24.0.10
set container name squid restart always

set container name squid port proxy source 3128
set container name squid port proxy destination 3128
set container name squid port proxy protocol tcp

set container name squid volume config source /config/squid/squid.conf
set container name squid volume config destination /etc/squid/squid.conf
set container name squid volume config mode ro

set container name squid volume cache source /config/squid/cache
set container name squid volume cache destination /var/spool/squid
set container name squid volume cache mode rw

commit
```

### OpenVPN Client

A VPN client in a container for routing traffic:

```bash
set container network vpn prefix 172.25.0.0/24

set container name ovpn-client image docker.io/dperson/openvpn-client:latest
set container name ovpn-client network vpn address 172.25.0.10
set container name ovpn-client restart always

set container name ovpn-client capability net-admin

set container name ovpn-client volume config source /config/openvpn/client.ovpn
set container name ovpn-client volume config destination /vpn/client.ovpn
set container name ovpn-client volume config mode ro

set container name ovpn-client volume auth source /config/openvpn/auth.txt
set container name ovpn-client volume auth destination /vpn/auth.txt
set container name ovpn-client volume auth mode ro

set container name ovpn-client device source /dev/net/tun
set container name ovpn-client device destination /dev/net/tun

commit
```

### Prometheus Monitoring

Metrics and monitoring:

```bash
set container network monitoring prefix 172.26.0.0/24

# Prometheus
set container name prometheus image docker.io/prom/prometheus:latest
set container name prometheus network monitoring address 172.26.0.10
set container name prometheus restart always

set container name prometheus port web source 9090
set container name prometheus port web destination 9090
set container name prometheus port web protocol tcp

set container name prometheus volume config source /config/prometheus/prometheus.yml
set container name prometheus volume config destination /etc/prometheus/prometheus.yml
set container name prometheus volume config mode ro

set container name prometheus volume data source /config/prometheus/data
set container name prometheus volume data destination /prometheus
set container name prometheus volume data mode rw

# Node Exporter (host metrics)
set container name node-exporter image docker.io/prom/node-exporter:latest
set container name node-exporter network monitoring address 172.26.0.11
set container name node-exporter restart always

set container name node-exporter port metrics source 9100
set container name node-exporter port metrics destination 9100
set container name node-exporter port metrics protocol tcp

# Grafana
set container name grafana image docker.io/grafana/grafana:latest
set container name grafana network monitoring address 172.26.0.12
set container name grafana restart always

set container name grafana port web source 3000
set container name grafana port web destination 3000
set container name grafana port web protocol tcp

set container name grafana volume data source /config/grafana
set container name grafana volume data destination /var/lib/grafana
set container name grafana volume data mode rw

set container name grafana environment GF_SECURITY_ADMIN_PASSWORD value 'admin123'

commit
```

## Operational Commands

### Viewing Containers

All containers:
```bash
show container
```

Example output:
```
NAME      STATE    IMAGE                           NETWORK
nginx     running  docker.io/library/nginx:latest  mynet
pihole    running  docker.io/pihole/pihole:latest  pihole
```

Container details:
```bash
show container nginx
```

### Viewing Images

```bash
show container image
```

### Viewing Networks

```bash
show container network
```

Example output:
```
NETWORK ID    NAME     DRIVER
abc123def456  mynet    bridge
```

### Container Logs

```bash
show container log nginx
```

Last 50 lines:
```bash
show container log nginx tail 50
```

### Restarting a Container

```bash
restart container nginx
```

### Pulling an Image

```bash
add container image docker.io/nginx:alpine
```

### Updating an Image

```bash
update container image nginx
```

Pulls a new version of the image (if available).

### Deleting a Container

```bash
delete container name nginx
commit
```

## Integration with VyOS

### Firewall for Containers

Protecting access to containers:

```bash
# Allow access to nginx only from LAN
set firewall ipv4 forward filter rule 100 action accept
set firewall ipv4 forward filter rule 100 destination address 172.20.0.10
set firewall ipv4 forward filter rule 100 destination port 80
set firewall ipv4 forward filter rule 100 source address 192.168.1.0/24
set firewall ipv4 forward filter rule 100 protocol tcp

set firewall ipv4 forward filter rule 101 action drop
set firewall ipv4 forward filter rule 101 destination address 172.20.0.10
set firewall ipv4 forward filter rule 101 destination port 80
set firewall ipv4 forward filter rule 101 protocol tcp

commit
```

### NAT for Containers

Containers with internet access through NAT:

```bash
# SNAT for the container network
set nat source rule 100 source address 172.20.0.0/16
set nat source rule 100 outbound-interface name eth0
set nat source rule 100 translation address masquerade

commit
```

DNAT for publishing a service:

```bash
# Forward port 80 of the external IP to the container
set nat destination rule 10 destination address 203.0.113.10
set nat destination rule 10 destination port 80
set nat destination rule 10 inbound-interface name eth0
set nat destination rule 10 protocol tcp
set nat destination rule 10 translation address 172.20.0.10
set nat destination rule 10 translation port 80

commit
```

### Routing for Containers

A static route for the container network:

```bash
set protocols static route 172.20.0.0/16 interface eth1
commit
```

### VRF Isolation

Containers in a separate VRF:

```bash
# Create a VRF
set vrf name CONTAINERS table 100
set vrf name CONTAINERS description 'Container network'

# Container network in the VRF
set container network mynet vrf CONTAINERS
set container network mynet prefix 172.20.0.0/16

commit
```

## Integration with Cloud Platforms

### Yandex Cloud

When deploying VyOS in Yandex Cloud, containers can be used to integrate with cloud services:

**Container Registry integration**:
```bash
# Using Yandex Container Registry
set container registry yandex address cr.yandex
set container registry yandex authentication username oauth
set container registry yandex authentication password '<yandex-oauth-token>'
commit

# Running a container from Yandex Container Registry
set container name myapp image cr.yandex/<registry-id>/myapp:latest
commit
```

**Monitoring with Yandex Monitoring**:
```bash
# Prometheus exporter for metrics in Yandex Monitoring
set container name unified-agent image cr.yandex/yc/unified-agent:latest
set container name unified-agent network monitoring
set container name unified-agent environment FOLDER_ID value '<folder-id>'
set container name unified-agent environment IAM_TOKEN value '<iam-token>'
commit
```

**Logging to Yandex Cloud Logging**:
```bash
# Fluent Bit for sending logs
set container name fluent-bit image cr.yandex/yc/fluent-bit:latest
set container name fluent-bit network monitoring
set container name fluent-bit volume config source /config/fluent-bit.conf
set container name fluent-bit volume config destination /fluent-bit/etc/fluent-bit.conf
set container name fluent-bit volume config mode ro
commit
```

### VK Cloud

Integration with VK Cloud (Mail.ru Cloud Solutions):

**VK Cloud Container Registry**:
```bash
# Configuring the registry for VK Cloud
set container registry vkcloud address hub.mcs.mail.ru
set container registry vkcloud authentication username '<username>'
set container registry vkcloud authentication password '<password>'
commit

# Running a container from the VK Cloud Registry
set container name myapp image hub.mcs.mail.ru/<project>/myapp:latest
commit
```

**S3-compatible storage**:
```bash
# MinIO client for integration with VK Cloud S3
set container name minio-client image docker.io/minio/mc:latest
set container name minio-client network storage
set container name minio-client environment MC_HOST_vkcloud value 'https://<access-key>:<secret-key>@hb.vkcs.cloud'
commit
```

## Troubleshooting

### Container Will Not Start

Check the status:
```bash
show container myapp
```

Check the logs:
```bash
show container log myapp
```

Journald logs:
```bash
journalctl -u vyos-container-myapp -n 50
```

### Image Will Not Pull

Check registry availability:
```bash
ping registry.example.com
```

Check DNS:
```bash
nslookup docker.io
```

Check authentication:
```bash
show container registry
```

### Network Issues

Check the container network:
```bash
show container network
```

Check the container IP:
```bash
show container myapp
```

Ping from VyOS:
```bash
ping 172.20.0.10
```

### Ports Are Not Reachable

Check port forwarding:
```bash
show configuration commands | grep "container name myapp port"
```

Check the firewall:
```bash
show firewall
```

Check NAT:
```bash
show nat source rules
show nat destination rules
```

### Volume Issues

Check permissions:
```bash
ls -la /config/myapp
```

Make sure the directory exists:
```bash
mkdir -p /config/myapp
```

### High Resource Usage

Check usage:
```bash
show container
```

Set limits:
```bash
set container name myapp cpu-quota 50
set container name myapp memory 512
commit
```

## Security

### Least Privilege

Run containers with minimal capabilities:

```bash
# Avoid
set container name myapp capability all

# Prefer
set container name myapp capability net-admin
```

### Network Isolation

Use separate networks for different applications:

```bash
set container network web prefix 172.20.0.0/24
set container network db prefix 172.21.0.0/24
```

### Read-only Volumes

Mount configuration as read-only:

```bash
set container name myapp volume config mode ro
```

### Regular Updates

Update images to receive security patches:

```bash
update container image myapp
restart container myapp
```

### Firewall Protection

Restrict access to containers through the firewall:

```bash
set firewall ipv4 forward filter rule 100 action accept
set firewall ipv4 forward filter rule 100 destination address 172.20.0.0/24
set firewall ipv4 forward filter rule 100 source address 192.168.1.0/24

set firewall ipv4 forward filter rule 999 action drop
set firewall ipv4 forward filter rule 999 destination address 172.20.0.0/24
```

### Resource Limits

Prevent DoS by limiting resources:

```bash
set container name myapp cpu-quota 50
set container name myapp memory 512
commit
```

## Performance

### Resource Allocation

Plan resources for containers:

**Recommendations**:
- Web server: 256-512 MB, CPU 25-50%
- Database: 1024-2048 MB, CPU 50-100%
- Monitoring: 512-1024 MB, CPU 25-50%

### Storage Performance

For databases, use separate disks:

```bash
# Mount an SSD for the database
set container name postgres volume data source /mnt/ssd/postgres
set container name postgres volume data destination /var/lib/postgresql/data
set container name postgres volume data mode rw
```

### Network Performance

Use MTU optimization:

```bash
set container network mynet mtu 9000
```

For jumbo frames on supported hardware.

## Limitations

- Podman runs in rootless mode with limitations
- Some containers require privileged mode (all capabilities)
- Graphical applications are not supported
- Large containers (>1GB RAM) may affect VyOS performance
- Containers restart when VyOS reboots

## Best Practices

1. **Use /config** - for persistent data
2. **Limit resources** - set CPU and memory limits
3. **Least privilege** - only the necessary capabilities
4. **Separate networks** - isolate by function
5. **Firewall protection** - control access
6. **Regular updates** - update images
7. **Monitoring** - track logs and resources
8. **Backups** - include /config/containers in the backup
9. **Testing** - verify containers before production
10. **Documentation** - describe the purpose of containers

## Additional Resources

- [VyOS Container Documentation](https://docs.vyos.io/en/latest/configuration/container/)
- [Podman Documentation](https://docs.podman.io/)
- [OCI Specification](https://opencontainers.org/)
- [Docker Hub](https://hub.docker.com/)

## Next Steps

- [Firewall](/docs/vyos/firewall/) - protecting containers
- [NAT](/docs/vyos/nat/) - publishing services
- [VRF](/docs/vyos/vrf/) - isolating container networks
- [System](/docs/vyos/system/) - monitoring resources

