Podman DNS

解決在 Podman Compose 上 DNS Server 無法使用的問題

本文將解析在使用 Podman Compose 時遇到的 DNS 服務器問題,並提供解決方案。

使用環境

作業系統為 Rocky Linux 8.7:

os-release

工具 podman-compose 版本如下:

podman-compose version: 1.0.7
podman version: 4.4.1

version

環境描述

由於部門都是在 LINE 上討論公事,常常造成公私不分,因此想架設一個 Rocket Chat 作為辦公的溝通平台,而 Rocket Chat 也有提供 docker-compose.yaml 讓用戶方便部署:

13個你不應該用Line辦公的理由: https://blog.teampel.com/2020/07/13-reasons-not-to-use-line.html

Rocket Chat: https://docs.rocket.chat/deploy/deploy-rocket.chat/deploy-with-docker-and-docker-compose

# src: https://github.com/RocketChat/Docker.Official.Image/blob/master/compose.yml
volumes:
  mongodb_data: { driver: local }

services:
  rocketchat:
    image: registry.rocket.chat/rocketchat/rocket.chat:${RELEASE:-latest}

    ...

    environment:
      MONGO_URL: "${MONGO_URL:-\
        mongodb://${MONGODB_ADVERTISED_HOSTNAME:-mongodb}:${MONGODB_INITIAL_PRIMARY_PORT_NUMBER:-27017}/\
        ${MONGODB_DATABASE:-rocketchat}?replicaSet=${MONGODB_REPLICA_SET_NAME:-rs0}}"

    ...

  mongodb:
    image: docker.io/bitnami/mongodb:${MONGODB_VERSION:-5.0}
    restart: always
    volumes:
      - mongodb_data:/bitnami/mongodb
    environment:
      MONGODB_REPLICA_SET_MODE: primary
      MONGODB_REPLICA_SET_NAME: ${MONGODB_REPLICA_SET_NAME:-rs0}

    ...

若使用 docker-compose 部署時沒有問題,但使用 podman-compose 部署時,便會發生 DNS 無法解析的問題,使得 rocketchat 無法連上 mongodb

podman-compose: https://github.com/containers/podman-compose

調查結果

  1. Docker 內建 DNS Server

經過調查,在 Docker 官方文件中可以得知在 docker-compose 中,DNS Server 是由 Docker daemon 所提供,而他的運作原理剛好在 COSCUP 2023 活動中,講者 hwchiu 有提到,有興趣的話可以參考他的演講:

Docker Network: https://docs.docker.com/network/

剖析 KIND(Kubernetes IN Docker) 的實作原理: https://www.slideshare.net/hongweiqiu/learned-from-kind

Containers that attach to a custom network use Docker's embedded DNS server. The embedded DNS server forwards external DNS lookups to the DNS servers configured on the host.

version

  1. Podman 需要 DNS Plugin

在 podman 中,因為沒有 Daemon 的關係,需要透過 Plugin 實現 DNS。官方文件中,有這麼一句話: Podman supports two network backends Netavark and CNI. Netavark is the default network backend and was added in Podman version 4.0. CNI is deprecated and will be removed in the next major Podman version 5.0, in preference of Netavark.

我們可以透過以下指令查看當前的 podman network backend:

podman info --format {{.Host.NetworkBackend}}

cni

如果沒有 Plugin,cni 是無法使用 DNS 的功能,我們可以透過 podman network inspect 查看預設的網路設定:

inspect

  1. 安裝 Plugin

一開始我以為直接將 network backend 切換為 netavark 就好,因為從官方描述中,看起來像是內建在 podman 4.0 中,但切換後卻得到以下錯誤,這代表主機並沒有安裝此 Plugin:

error

可以透過 dnf 直接安裝 netavark,並重新設定 podman 環境:

過去可以透過 dnf install -y podman-dnsname 安裝 dnsname Plugin,但此專案已經停止維護: https://github.com/containers/dnsname

dnf install -y netavark

netavark

  1. 重設 network backend

以下步驟參考 Oracle Linux 的 Podman User’s Guide,內容詳細介紹如何切換 network backend。根據 GitHub 上關於 Container 的 Common Library 的描述,Container Engine 預設使用 containers.conf 作為設定檔案,因此第一步先建立設定檔:

Podman Common: https://github.com/containers/common/blob/main/docs/containers.conf.5.md

cp /usr/share/containers/containers.conf /etc/containers/

修改 /etc/containers/containers.conf,將 network_backend 改為 netavark:

network_backend = "netavark"

初始化 Podman 設置:

podman system reset
  1. 驗證 network backend

再次執行查看指令,可以看到 network backend 已經改為 netavark:

podman info --format {{.Host.NetworkBackend}}

netavark-info

也可以透過 ss 指令或 ps 指令查看,可以發現 netavark 使用 aardvark-dns 建立一個 dns server,並且佔用 53 port:

ss -tuanp

ps -ef | grep aardvark-dns

ps

執行結果

修改完 Podman DNS 設定後,Rocket Chat 也成功執行了:

start

Reference