Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/pages/managing-providers/add-provider.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ sidebar_label: Add a Provider
The Devsy team maintains providers for popular services such as:

- [Docker (docker)](https://github.com/devsy-org/devsy/tree/main/providers/docker)
- [Podman (podman)](https://github.com/devsy-org/devsy/tree/main/providers/podman)
- [Kubernetes (kubernetes)](https://github.com/devsy-org/devsy-provider-kubernetes)
- [SSH (ssh)](https://github.com/devsy-org/devsy-provider-ssh)
- [AWS (aws)](https://github.com/devsy-org/devsy-provider-aws)
Expand Down Expand Up @@ -235,7 +236,6 @@ The community maintains providers for additional services.
- [Open Telekom Cloud (akyriako/devsy-provider-opentelekomcloud)](https://github.com/akyriako/devsy-provider-opentelekomcloud)
- [Vultr (navaneeth-dev/devsy-provider-vultr)](https://github.com/navaneeth-dev/devsy-provider-vultr)
- [STACKIT (stackitcloud/devsy-provider-stackit)](https://github.com/stackitcloud/devsy-provider-stackit)
- [Podman (kuju63/devsy-provider-podman)](https://github.com/kuju63/devsy-provider-podman)

These providers can be installed with the Devsy CLI in the following form:
```
Expand Down
38 changes: 38 additions & 0 deletions docs/pages/troubleshooting/linux-troubleshooting.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,41 @@ append `:Z` to your volume definitions, like so

There is a [known issue](https://github.com/devsy-org/devsy/issues/1045) where some linux distros use a large PATH to find SSH and causes the connection string to be too long. The workaround is to specify
the SSH binary explicitly in vscode.

### Podman

#### Rootless socket path

Rootless Podman places its socket at `$XDG_RUNTIME_DIR/podman/podman.sock`. If Devsy cannot connect, `PODMAN_HOST` is likely unset. Set it explicitly:

```bash
devsy provider set-options podman --option PODMAN_HOST=unix:///run/user/$(id -u)/podman/podman.sock
```

#### `podman compose` vs `docker-compose`

Podman v4+ ships `podman compose` as a built-in subcommand. If your `devcontainer.json` or workspace scripts call `docker-compose` directly, they will fail. Update references to `podman compose`, or add a shell alias as a stopgap:

```bash
alias docker-compose='podman compose'
```

`devsy up` handles this automatically — Devsy's compose helper detects Podman via the `ContainerRuntime` interface. The alias is only needed for scripts that run inside the workspace itself.

#### BuildKit not available

Podman uses buildah internally for `podman build`. Dockerfiles with the `# syntax=docker/dockerfile:1` pragma or BuildKit-specific `RUN --mount` syntax will fail. Remove the syntax pragma and restructure affected `RUN` steps to avoid BuildKit mounts. Most standard Dockerfiles build without changes.

#### Volume mount permissions in rootless mode

Rootless Podman maps UIDs through user namespaces. Files created inside the container appear owned by `nobody` on the host.

Comment on lines +94 to +95

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Make ownership outcome less absolute.

Line 94 says files appear as nobody, but rootless mappings can appear as different numeric UIDs/GIDs depending on subuid/subgid setup. Soften wording to avoid inaccurate troubleshooting expectations.

Suggested doc tweak
-Rootless Podman maps UIDs through user namespaces. Files created inside the container appear owned by `nobody` on the host.
+Rootless Podman maps UIDs through user namespaces. Files created inside the container may appear owned by an unexpected UID/GID (sometimes shown as `nobody`) on the host.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Rootless Podman maps UIDs through user namespaces. Files created inside the container appear owned by `nobody` on the host.
Rootless Podman maps UIDs through user namespaces. Files created inside the container may appear owned by an unexpected UID/GID (sometimes shown as `nobody`) on the host.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/pages/troubleshooting/linux-troubleshooting.mdx` around lines 94 - 95,
Change the absolutist sentence that "Files created inside the container appear
owned by `nobody` on the host" to a softened statement: note that Rootless
Podman maps UIDs via user namespaces and files on the host can show as `nobody`
or as other numeric UIDs/GIDs depending on the system's subuid/subgid mappings;
update the paragraph beginning "Rootless Podman maps UIDs through user
namespaces." to reflect this variability and mention checking subuid/subgid
configuration when ownership looks unexpected.

**With SELinux**: append `:Z` to volume mounts (see [Using SELinux](#using-selinux) above).

**Without SELinux**: fix ownership with `podman unshare`:

```bash
podman unshare chown -R $(id -u):$(id -g) /path/to/volume
```

If rootless UID mapping is too restrictive for your workflow, run the container as root using `sudo podman` instead.
184 changes: 184 additions & 0 deletions docs/pages/tutorials/podman-provider-setup.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
---
title: Podman Provider Setup
sidebar_label: Podman Provider Setup
---

## Purpose

Podman is a first-class provider in Devsy. It runs containers without a background daemon — each container is a direct child of the calling process — which eliminates the single-point-of-failure that a persistent Docker daemon introduces. Podman is OCI-compatible, so existing `devcontainer.json` configurations work without changes.

This tutorial walks through installing Podman on your platform, registering it as a Devsy provider, and starting a workspace.

## Prerequisites

Install Podman for your platform before registering it as a Devsy provider.

### Linux

Install `podman` from your distribution's package manager:

```bash
# Debian / Ubuntu
sudo apt-get install -y podman

# Fedora / RHEL / CentOS
sudo dnf install -y podman

# Arch Linux
sudo pacman -S podman
```

### macOS

Install via Homebrew or download [Podman Desktop](https://podman-desktop.io):

```bash
brew install podman
podman machine init
podman machine start
```

### Windows

Podman on Windows runs inside WSL2. Install WSL2 first, then install Podman inside your WSL distro.

**Step 1 — Enable WSL2.** Run the following in **PowerShell (as Administrator)** and restart when prompted:

```powershell
wsl --install
```

**Step 2 — Install Podman inside WSL.** Open your WSL terminal and run:

```bash
sudo apt-get update && sudo apt-get install -y podman
```

**Step 3 — Verify the socket is reachable from Windows.** Note the socket path — you will need it for the `PODMAN_HOST` option:

```bash
echo $XDG_RUNTIME_DIR/podman/podman.sock
```
Comment on lines +57 to +61

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clarify execution context for the socket check.

Line 57 says “reachable from Windows,” but the command shown is executed in WSL and only prints the Linux-side socket path. Rewording avoids confusion.

Suggested doc tweak
-**Step 3 — Verify the socket is reachable from Windows.** Note the socket path — you will need it for the `PODMAN_HOST` option:
+**Step 3 — Verify the Podman socket path inside WSL.** Note this path — you will need it for the `PODMAN_HOST` option:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/pages/tutorials/podman-provider-setup.mdx` around lines 57 - 61, The
text "Verify the socket is reachable from Windows" is misleading because the
shown command (echo $XDG_RUNTIME_DIR/podman/podman.sock) runs in WSL and only
prints the Linux-side path; update Step 3 wording to clarify the execution
context by stating that the command should be run inside WSL (or the Linux
environment) to display the socket path and separately instruct how to confirm
Windows can reach that socket (for example by translating the path or testing
with a Windows-side client), and keep the example command `echo
$XDG_RUNTIME_DIR/podman/podman.sock` as the WSL-specific step.


## Adding the Podman Provider

Register the built-in Podman provider with Devsy:

```bash
devsy provider add podman
```

Devsy registers `podman` as an available provider. Confirm it appears in your provider list:

```bash
devsy provider list
```

## Configuration Options

The Podman provider exposes three options:

| Option | Default | Description |
|--------|---------|-------------|
| `PODMAN_PATH` | `podman` | Path to the `podman` binary. Override when `podman` is not on `PATH` — for example, `/usr/local/bin/podman`. |
| `PODMAN_HOST` | *(unset)* | Podman host socket or TCP address (sets `DOCKER_HOST` internally). Required on Windows to point Devsy at the WSL socket, e.g. `unix:///run/user/<UID>/podman/podman.sock` (replace `<UID>` with `id -u`). |
| `INACTIVITY_TIMEOUT` | *(unset)* | Stops the container after the specified idle period. Accepts duration strings such as `10m` or `1h`. |

Set options after adding the provider using `--option` flags:

```bash
devsy provider set-options podman --option PODMAN_PATH=/usr/local/bin/podman
```

To see available options before setting them:

```bash
devsy provider options podman
```

Or pass options inline at add time:

```bash
devsy provider add podman -o PODMAN_PATH=/usr/local/bin/podman -o INACTIVITY_TIMEOUT=1h
```

## Rootless vs Rootful Setup

Podman can run in two modes:

| Mode | How it works | When to use |
|------|-------------|-------------|
| **Rootless** (default) | Containers run as your user. User namespaces isolate processes from the host. | Recommended for most development workflows. Reduces the blast radius of a compromised container. |
| **Rootful** | Containers run as root inside a Podman machine. | Required when a container needs to bind-mount paths owned by root, or when certain network configurations (e.g. macvlan) are needed. |

**macOS / Windows — switching machine mode:**

```bash
# Initialize a new rootful machine (replaces the default rootless one)
podman machine init --rootful

# Or upgrade an existing machine in-place
podman machine set --rootful
podman machine stop && podman machine start
```

**Linux — rootless is the system default.** To run rootful containers, prefix commands with `sudo` or add your user to the `wheel` / `sudo` group and run `podman system service` as root.

:::info
After switching to rootful mode on macOS or Windows, update the `PODMAN_HOST` option in Devsy to point to the rootful socket. The rootful socket path is typically `/run/podman/podman.sock` (inside the VM).
:::

## Creating a Workspace with Podman

Start a workspace using the Podman provider by passing `--provider podman` to `devsy up`:

```bash
devsy up --provider podman --id my-workspace https://github.com/my-org/my-repo
```

Devsy builds the workspace image using `podman build` and starts the container. When the workspace is ready, connect to it:

```bash
devsy ssh my-workspace
```

A successful `devsy ssh` connection confirms the workspace is running under Podman. To verify the Podman binary inside the workspace:

```bash
podman --version
```
Comment on lines +145 to +149

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use a provider/runtime verification step instead of checking podman inside the workspace.

Line 145 suggests podman --version inside the workspace, but workspace containers often won’t include Podman CLI. This can produce a false failure in an otherwise-correct setup.

Suggested doc tweak
-A successful `devsy ssh` connection confirms the workspace is running under Podman. To verify the Podman binary inside the workspace:
+A successful `devsy ssh` connection confirms the workspace is running. To verify Podman is the active runtime, check from the host:
 
 ```bash
-podman --version
+devsy provider list
+# or inspect running containers with:
+podman ps
</details>

<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
A successful `devsy ssh` connection confirms the workspace is running. To verify Podman is the active runtime, check from the host:

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/pages/tutorials/podman-provider-setup.mdx` around lines 145 - 149,
Replace the in-workspace check that tells users to run "podman --version" (which
can fail because workspace images may not include the Podman CLI) with
provider/runtime verification commands: instruct users to run "devsy provider
list" to confirm the provider is Podman and/or run "podman ps" on the host to
inspect running containers; update the text around the former "podman --version"
mention to show these alternative commands ("devsy provider list" and "podman
ps") and remove the in-container Podman version check.


## Troubleshooting Common Issues

### Socket not found or permission denied

Devsy cannot reach the Podman socket. Check that the Podman machine is running:

```bash
podman machine list
podman machine start # if the machine is stopped
```

On Linux, confirm the user socket exists:

```bash
ls -la $XDG_RUNTIME_DIR/podman/podman.sock
```

If the socket path differs from the default, set `PODMAN_HOST` to the correct path:

```bash
devsy provider set-options podman --option PODMAN_HOST=unix:///run/user/$(id -u)/podman/podman.sock
```

### Dockerfile features not supported during image build

Podman uses Buildah for image builds, not Docker BuildKit. Most Dockerfiles are compatible, but a small number of BuildKit-specific syntax extensions (e.g. `RUN --mount=type=cache` with the `buildkit` frontend) may fail or behave differently. If your workspace image uses BuildKit-only syntax, remove the `# syntax=docker/dockerfile:1` pragma or restructure the affected `RUN` steps.

### `podman compose` vs `docker-compose`

Podman v4+ ships `podman compose` as a built-in subcommand backed by the `podman-compose` Python library. It is compatible with `docker-compose` v2 syntax for most workloads. If your `devcontainer.json` or workspace scripts call `docker-compose` directly, replace those calls with `podman compose` or create a shell alias:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

According to official Podman documentation, is podman compose always a built-in implementation, or does it delegate to external providers (such as docker-compose or podman-compose) depending on configuration/version?

💡 Result:

Yes. Per the official Podman documentation, podman compose is “a thin wrapper around an external compose provider” (e.g., docker-compose or podman-compose), and it passes the specified options plus the command/arguments directly to that provider. By default, the compose providers are docker-compose and podman-compose, with docker-compose taking precedence if installed. The provider can be changed via the compose_providers setting in containers.conf(5) (or the PODMAN_COMPOSE_PROVIDER environment variable), so it is not always a built-in implementation of Compose itself; it delegates to whichever external provider is configured/available. [1]

Citations:


Remove inaccurate claim about podman compose implementation.

Line 180 states that podman compose is "a built-in subcommand backed by the podman-compose Python library." According to official Podman documentation, podman compose is a thin wrapper around external compose providers (such as docker-compose or podman-compose), not a built-in implementation. The backing provider is configurable and not always podman-compose. Use neutral wording that focuses on compatibility instead:

Podman v4+ includes the podman compose command, which is compatible with docker-compose v2 syntax for most workloads.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/pages/tutorials/podman-provider-setup.mdx` at line 180, Replace the
inaccurate sentence that claims "podman compose" is "a built-in subcommand
backed by the `podman-compose` Python library" with neutral wording stating that
Podman v4+ includes the `podman compose` command and that it is compatible with
`docker-compose` v2 syntax for most workloads; update the paragraph containing
the phrase "podman compose" so it no longer asserts a specific backing provider
and instead notes that the backing provider can vary.


```bash
alias docker-compose='podman compose'
```
4 changes: 4 additions & 0 deletions docs/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,10 @@ module.exports = {
type: "doc",
id: "tutorials/docker-provider-via-wsl",
},
{
type: "doc",
id: "tutorials/podman-provider-setup",
},
],
},
{
Expand Down
Loading