# 4.使用 Podman

{% hint style="success" %}
对应的[官方页面地址](https://github.com/dani-garcia/vaultwarden/wiki/Using-Podman)
{% endhint %}

[Podman](https://podman.io/) 是替代 Docker 的无守护程序，它与大部分 Docker 容器兼容。

## 创建 Quadlet（适用于 Podman 4.4+） <a href="#creating-a-quadlet-podman-4.4" id="creating-a-quadlet-podman-4.4"></a>

从版本 4.4 开始，Podman 使用 [quadlets](https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html)，如果您使用以前的 `generate systemd` 方法，则会显示一个警告。

额外的好处是此方法将使容器保持更新。

### 通过环境文件配置 <a href="#configuration-via-environment-file" id="configuration-via-environment-file"></a>

在环境文件中进行配置可能会更容易并且不易出错。

注意：此文件包含机密，请确保只有 root 拥有访问权限！

```shell
sudo install -o0 -g0 -m600 /dev/null /etc/vaultwarden.env
sudo vi /etc/vaultwarden.env
```

```systemd
# Contents of /etc/vaultwarden.env
ROCKET_PORT=8080

# DISABLE_ADMIN_TOKEN=true
# ADMIN_TOKEN=$argon2id$...

# LOG_LEVEL=debug
```

### 创建 podman Quadlet <a href="#creating-the-podman-quadlet" id="creating-the-podman-quadlet"></a>

配置看起来像 systemd 的，但我们配置的是容器，而不是单元。请参阅所有 `[Container]` 指令的[文档](https://man.archlinux.org/man/quadlet.5.en#Container_units_%5BContainer%5D)。

```systemd
# Content of /usr/share/containers/systemd/vaultwarden.container
[Unit]
Description=Vaultwarden container
After=network-online.target

[Container]
AutoUpdate=registry
Image=ghcr.io/dani-garcia/vaultwarden:latest
Exec=/start.sh
EnvironmentFile=/etc/vaultwarden.env
Volume=/vw-data/:/data/
PublishPort=8080:8080

[Install]
WantedBy=default.target
```

编辑 quadlet 后，运行 `systemctl daemon-reload` 以创建或更新 systemd 单元。您可以使用常规的 `systemctl` 命令控制此容器，例如 `systemctl start vaultwarden.service` 。

### 自动更新 <a href="#auto-update" id="auto-update"></a>

[自动更新](https://docs.podman.io/en/latest/markdown/podman-auto-update.1.html#description)可自动执行更新过程：

```sh
sudo podman auto-update
```

或者，您可以启用定时器，它会每天自动更新（默认情况。也可以编辑）：

```sh
sudo systemctl enable podman-auto-update.timer
```

## 创建 systemd 服务文件（适用于老版本的 Podman） <a href="#creating-a-systemd-service-file-older-podman-versions" id="creating-a-systemd-service-file-older-podman-versions"></a>

由于 Podman 的无守护程序架构，它比 Docker 更容易在 systemd 中运行。它带有一个便捷的 [generate syetemd 命令](http://docs.podman.io/en/latest/markdown/podman-generate-systemd.1.html)，该命令可以生成 systemd 文件。[这一篇不错的文章详细介绍了它](https://www.redhat.com/zh/blog/podman-shareable-systemd-services)，还有[这篇文章也详细介绍了一些最新的更新](https://www.redhat.com/zh/blog/improved-systemd-podman)。

```systemd
$ podman run -d --name vaultwarden -v /vw-data/:/data/:Z -e ROCKET_PORT=8080 -p 8080:8080 vaultwarden/server:latest
54502f309f3092d32b4c496ef3d099b270b2af7b5464e7cb4887bc16a4d38597
$ podman generate systemd --name vaultwarden
# container-foo.service
# autogenerated by Podman 1.6.2
# Tue Nov 19 15:49:15 CET 2019

[Unit]
Description=Podman container-foo.service
Documentation=man:podman-generate-systemd(1)

[Service]
Restart=on-failure
ExecStart=/usr/bin/podman start vaultwarden
ExecStop=/usr/bin/podman stop -t 10 vaultwarden
KillMode=none
Type=forking
PIDFile=/run/user/1000/overlay-containers/54502f309f3092d32b4c496ef3d099b270b2af7b5464e7cb4887bc16a4d38597/userdata/conmon.pid

[Install]
WantedBy=multi-user.target default.target
```

您可以提供 `--files` 标志告诉 podman 将 systemd 服务放到某个文件中，或使用 `podman generate systemd --name vaultwarden > /etc/systemd/system/container-vaultwarden.service`。这样，我们就可以像任何正常的服务文件一样启用和启动容器了。

```shell
$ systemctl --user enable /etc/systemd/system/container-vaultwarden.service
$ systemctl --user start container-vaultwarden.service
```

### 每次重启时新建容器 <a href="#new-container-every-restart" id="new-container-every-restart"></a>

如果我们希望每次服务启动时都创建一个新的容器，可以使用 `podman generate systemd --new` 命令生成一个重新创建容器的服务文件：

```shell
$ podman generate systemd --new --name vaultwarden
```

如果您使用的是旧版 Podman，则可以编辑服务文件以包含如下内容：

```systemd
[Unit]
Description=Podman container-vaultwarden.service

[Service]
Restart=on-failure
ExecStartPre=/usr/bin/rm -f /%t/%n-pid /%t/%n-cid
ExecStart=/usr/bin/podman run --conmon-pidfile /%t/%n-pid --cidfile /%t/%n-cid --env-file=/home/spytec/Vaultwarden/vaultwarden.conf -d -p 8080:8080 -v /home/spytec/Vaultwarden/vw-data:/data/:Z vaultwarden/server:latest
ExecStop=/usr/bin/podman stop -t "15" --cidfile /%t/%n-cid
ExecStop=/usr/bin/podman rm -f --cidfile /%t/%n-cid
KillMode=none
Type=forking
PIDFile=/%t/%n-pid

[Install]
WantedBy=multi-user.target default.target
```

环境文件 `vaultwarden.conf` 可以包含您需要的容器的所有环境值，比如：

```systemd
ROCKET_PORT=8080
```

如果您希望此容器拥有特定的名称，则需要添加 `ExecStartPre=/usr/bin/podman rm -i -f vaultwarden`，如果进程未被正确清理的话。注意，此方式当前无法与具有 `User=` 选项的用户一起正常工作（见 [https://github.com/containers/podman/issues/5572](https://github.com/wcjxixi/Vaultwarden-Wiki-Chn/blob/master/container-image-usage/%20https:/github.com/containers/podman/issues/5572/README.md)）。

## 故障排除 <a href="#troubleshooting" id="troubleshooting"></a>

### 调试 systemd 服务文件 <a href="#debugging-systemd-service-file" id="debugging-systemd-service-file"></a>

如果主机出现故障或容器崩溃，则 systemd 服务文件应自动停止现有容器并将其重新启动。可以通过 `journalctl --user -u container-vaultwarden -t 100` 来定位错误。

在大多数情况下，我们可以通过简单地增加服务文件中的 podman 命令的超时时间来解决我们看到的错误。

### 充分利用 Vaultwarden 和数据库的 quadlet 文件

应用程序和 PostgreSQL 数据库被容器化并放置在 pod 中。应用程序通过 Podman 网络功能使用自己的网络。持久卷用于数据库数据和 Vaultwarden 应用程序数据。部署容器使用的机密由 Podman 机密功能管理。

{% @mermaid/diagram content="flowchart TD
A(vaultwarden.network) --- B(vaultwarden.pod)
B --- C(vaultwarden-app.container)
B --- D(vaultwarden-db.container)
C --- G\[/env\_file=/etc/vaultwarden/config/]
C --- E\[(vaultwarden-app.volume)]
D --- F\[(vaultwarden-db.volume)]
D --- H\[/env\_file=/home/vaultwarden/vaultwarden/vaultwarden-db.env/]
C --- I{{podman-secret: database\_url, admin\_token}}
D --- J{{podman-secret: postgres\_password}}
style A fill:#ffec99
style B fill:#ffc9c9
style C fill:#b2f2bb
style D fill:#b2f2bb
style E fill:#a5d8ff
style F fill:#a5d8ff
style G fill:#f08c00
style H fill:#f08c00
style I fill:#d0bfff
style J fill:#d0bfff" %}

该基础设施使用以下 quadlet 文件定义：

* `vaultwarden-app.container`
* `vaultwarden-app.volume`
* `vaultwarden-db.container`
* `vaultwarden-db.volume`
* `vaultwarden.network`
* `vaultwarden.pod`

#### Pod 的定义 <a href="#definition-of-the-pod" id="definition-of-the-pod"></a>

创建 `~/.config/containers/systemd/vaultwarden.pod` 文件：

```systemd
[Pod]
PodName=vaultwarden
Network=vaultwarden.network
PublishPort=8080:8080
```

#### 网络的定义 <a href="#definition-of-the-network" id="definition-of-the-network"></a>

创建 `~/.config/containers/systemd/vaultwarden.network` 文件：

```systemd
[Network]
NetworkName=vaultwarden
Gateway=192.168.220.1
Subnet=192.168.220.0/24
```

#### 持久卷的定义 <a href="#definition-of-the-persistent-volumes" id="definition-of-the-persistent-volumes"></a>

创建 `~/.config/containers/systemd/vaultwarden-app.volume` 文件：

```systemd
[Volume]
VolumeName=vaultwarden-app
```

以及 `~/.config/containers/systemd/vaultwarden-db.volume` 文件：

```systemd
[Volume]
VolumeName=vaultwarden-db
```

#### 容器的定义 <a href="#definition-of-the-containers" id="definition-of-the-containers"></a>

创建 `~/.config/containers/systemd/vaultwarden-app.container` 文件：

```systemd
[Container]
ContainerName=vaultwarden-app
EnvironmentFile=/etc/vaultwarden/config
HealthCmd=/healthcheck.sh
HealthInterval=120s
HealthRetries=10
HealthTimeout=45s
Image=docker.io/vaultwarden/server:1.34.3
Pod=vaultwarden.pod
Secret=database_url,type=env,target=DATABASE_URL
Secret=admin_token,type=env,target=ADMIN_TOKEN
Volume=vaultwarden-app.volume:/data
[Unit]
Requires=vaultwarden-db.service
After=vaultwarden-db.service

[Install]
WantedBy=default.target
```

以及 `~/.config/containers/systemd/vaultwarden-db.container` 文件：

```systemd
[Container]
ContainerName=vaultwarden-db
EnvironmentFile=/home/vaultwarden/vaultwarden/vaultwarden-db.env
HealthCmd=/usr/bin/pg_isready -q -d vaultwarden -U vaultwarden
HealthInterval=120s
HealthRetries=10
HealthTimeout=45s
Image=docker.io/library/postgres:17
Pod=vaultwarden.pod
Secret=postgres_password,type=env,target=POSTGRES_PASSWORD
Volume=vaultwarden-db.volume:/var/lib/postgresql/data

[Install]
WantedBy=default.target
```

#### 配置 <a href="#configuration" id="configuration"></a>

使用环境文件 `/etc/vaultwarden/config` 和 `~/vaultwarden/vaultwarden-db.env` 完成配置。

在 `~/vaultwarden/vaultwarden-db.env` 文件中设置变量 `POSTGRES_USER` 和 `POSTGRES_DB` 。

#### 机密 <a href="#secrets" id="secrets"></a>

您需要定义机密 `postgres_password`、`database_url` 和 `admin_token`：

我假设 `POSTGRES_USER=vaultwarden` 和 `POSTGRES_DB=vaultwarden`&#x20;

```bash
openssl rand -base64 32|podman secret create postgres_password -
echo "postgres://vaultwarden:$(podman secret inspect --showsecret --format '{{.SecretData}}' postgres_password)@vaultwarden-db/vaultwarden" | tr -d '\n' | podman secret create database_url -
echo -n "MySecretPassword" | argon2 "$(openssl rand -base64 32)" -e -id -k 65540 -t 3 -p 4| tr -d '\n' | podman secret create admin_token -
```

#### 部署 <a href="#deploy" id="deploy"></a>

```bash
systemctl --user daemon-reload
systemctl --user start vaultwarden-pod.service
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://rs.ppgg.in/container-image-usage/using-podman.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
