1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

dockerコンテナ内でrootlessによるコンテナ実行をしたい

Posted at

前提

  • K8s でなんらかのサービスを提供しているときに、そのサービス内でユーザ権限によるコンテナ実行をしたい
  • ユーザは winbind により ActiveDirectory で認証

手段としては以下のいずれかが考えられる。

  • DinD:Docker-inside-Docker による rootless コンテナ実行
  • DooD: Docker-outside-of-Docker による rootless コンテナ実行
  • podman によるユーザ権限でのコンテナ実行

DinD による rootless コンテナ実行の試行

結論から言うとできない。

DinD を行う場合は docker 公式イメージの docker:dind タグなどを用いることが多いが、これは主に GitHub Actions におけるコンテナ内でイメージビルドを行う際に使うもの。

独自サービス内でコンテナ起動をしたいため、ベースイメージは好きなものを使いたい。

CentOSイメージを使用したDinD
を参考に、dockerインストールを試みる。

docker インストール

https://docs.docker.com/engine/install/rhel/
に従えば、インストールはすんなりできた。

[root@xxxxxxxx /]# dnf -y install dnf-plugins-core
[root@xxxxxxxx /]# dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo
[root@xxxxxxxx /]# dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

が、systemd が入っていないため systemctl による docker サービス起動ができない。

[root@xxxxxxxx /]# systemctl enable --now docker
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down

dockerd 直接起動を実施したが、エラーになる。

[root@xxxxxxxx /]# dockerd
INFO[******************] Starting up                                  
INFO[******************] containerd not running, starting managed containerd 
INFO[******************] started new containerd process                address=/var/run/docker/containerd/containerd.sock module=libcontainerd pid=205

...

INFO[******************] unable to detect if iptables supports xlock: 'iptables --wait -L -n': `iptables v1.8.5 (nf_tables): Could not fetch rule set generation id: Permission denied (you must be root)`  error="exit status 4"
INFO[******************] stopping event stream following graceful shutdown  error="<nil>" module=libcontainerd namespace=moby
INFO[******************] stopping healthcheck following graceful shutdown  module=libcontainerd
INFO[******************] stopping event stream following graceful shutdown  error="context canceled" module=libcontainerd namespace=plugins.moby
failed to start daemon: Error initializing network controller: error obtaining controller instance: failed to register "bridge" driver: failed to create NAT chain DOCKER: iptables failed: iptables -t nat -N DOCKER: iptables v1.8.5 (nf_tables): Could not fetch rule set generation id: Permission denied (you must be root)

 (exit status 4)

ということで rootless 設定以前にdockerサービス実行できない。

DooD による rootless コンテナ実行の試行

DinD では docker サービス起動時に iptables によるブリッジインタフェースの生成に失敗している様子だったため、 DooD で回避できるかどうかを試行。

$ docker run -it -v /var/run/docker.sock:/var/run/docker.sock ...  --rm [service-container] bash

## docker インストール用リポジトリ追加
[root@xxxxxxxx /]# dnf -y install dnf-plugins-core
[root@xxxxxxxx /]# dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo

## docker-cli のみインストール
[root@xxxxxxxx /]# dnf install -y docker-ce-cli

確かに docker ps コマンドで実行ホストのコンテナ群が見えた (見えてしまった)。

[root@xxxxxxxx /]# docker ps
CONTAINER ID   IMAGE                               COMMAND                  CREATED          STATUS                 PORTS                    NAMES
***********   busybox                             "sleep 3600"             41 minutes ago   Up 41 minutes                                   k8s_pod-01a_pod-01a_default_************
***********   busybox                             "sleep 3600"             41 minutes ago   Up 41 minutes                                   k8s_pod-01_pod-01_default_**********
...

rootless docker インストール

この状態で rootless docker ができるかを試したが、失敗。

ローカルユーザ追加

[root@xxxxxxxx /]# adduser testuser

この状態で testuser 指定でコンテナに入り rootless を設定。

$ docker exec -it -u testuser xxxxxxxx bash

[testuser@xxxxxxxx /]$ curl -fsSL https://get.docker.com/rootless | sh
# Installing stable version 27.3.1
# Executing docker rootless install script, commit: 6b775c4
# Existing rootless Docker detected at /home/testuser/bin/dockerd

# To reinstall or upgrade rootless Docker, run the following commands and then rerun the installation script:
systemctl --user stop docker
rm -f /home/testuser/bin/dockerd

# Alternatively, install the docker-ce-rootless-extras RPM/deb package for ease of package management (requires root).
# See https://docs.docker.com/go/rootless/ for details.

https://docs.docker.com/engine/security/rootless/#errors-when-starting-the-docker-daemon
に "could not get XDG_RUNTIME_DIR" という項目があり、環境変数 XDG_RUNTIME_DIR がセットされていなかったため強引にセットして起動してみたが、権限エラーになる。

[testuser@xxxxxxxx /]$ export XDG_RUNTIME_DIR=$HOME/.docker/xrd
[testuser@xxxxxxxx /]$ rm -rf $XDG_RUNTIME_DIR
[testuser@xxxxxxxx /]$ mkdir -p $XDG_RUNTIME_DIR
[testuser@xxxxxxxx /]$ dockerd-rootless.sh

...

+ exec rootlesskit --state-dir=/home/testuser/.docker/xrd/dockerd-rootless --net=slirp4netns --mtu=65520 --slirp4netns-sandbox=auto --slirp4netns-seccomp=auto --disable-host-loopback --port-driver=builtin --copy-up=/etc --copy-up=/run --propagation=rslave /home/testuser/bin/dockerd-rootless.sh
WARN[0000] [rootlesskit:parent] The host root filesystem is mounted as "master:1575". Setting child propagation to "rslave" is not supported. 
[rootlesskit:parent] error: failed to start the child: fork/exec /proc/self/exe: operation not permitted

rootless docker は DooD でもできなさそうな感じ。

podman によるユーザ権限でのコンテナ実行

コンテナに入り podmanを dnf インストールする。

$ docker run -it --rm [service-container] bash
[root@xxxxxxx /]# dnf install -y podman

だが podmanで適当なコンテナを実行しようとするとエラーになる。

[root@xxxxxxx /]# podman run hello-world
WARN[0000] "/" is not a shared mount, this could cause issues or missing mounts with rootless containers 
cannot clone: Operation not permitted
Error: cannot re-exec process

によれば、 docker 実行時に --security-opt seccomp=unconfined を付けると良いらしい。

$ docker run -it --security-opt seccomp=unconfined --rm [service-container] bash
[root@xxxxxxxxx /]# dnf install -y podman
[root@xxxxxxxxx /]# podman run hello-world
WARN[0000] "/" is not a shared mount, this could cause issues or missing mounts with rootless containers 
Resolved "hello-world" as an alias (/etc/containers/registries.conf.d/000-shortnames.conf)
Trying to pull quay.io/podman/hello:latest...
Getting image source signatures
Copying blob 81df7ff16254 done   | 
Copying config 5dd467fce5 done   | 
Writing manifest to image destination
ERRO[0003] Unmounting /var/lib/containers/storage/overlay/885a8ae8337b760ac777ab466e2a72974d258477107a5594ebb927a716e89b54/merged: invalid argument 
WARN[0003] Failed to load cached network config: network podman not found in CNI cache, falling back to loading network podman from disk 
ERRO[0003] Preparing container d6b42ea4963f7264ab229bab8b4c201639cfca2330c840308b7c90ce9dfc9169: plugin type="bridge" failed (add): cni plugin bridge failed: failed to create bridge "cni-podman0": could not add "cni-podman0": operation not permitted 
Error: mounting storage for container d6b42ea4963f7264ab229bab8b4c201639cfca2330c840308b7c90ce9dfc9169: creating overlay mount to /var/lib/containers/storage/overlay/885a8ae8337b760ac777ab466e2a72974d258477107a5594ebb927a716e89b54/merged, mount_data="lowerdir=/var/lib/containers/storage/overlay/l/SBCUSNZOXDGNIQ6SDMWKBGA7VK,upperdir=/var/lib/containers/storage/overlay/885a8ae8337b760ac777ab466e2a72974d258477107a5594ebb927a716e89b54/diff,workdir=/var/lib/containers/storage/overlay/885a8ae8337b760ac777ab466e2a72974d258477107a5594ebb927a716e89b54/work,nodev": using mount program /usr/bin/fuse-overlayfs: unknown argument ignored: lazytime
fuse: device not found, try 'modprobe fuse' first
fuse-overlayfs: cannot mount: No such file or directory
: exit status 1

podman コマンドは実行できたが、"/" が shared でないという警告や、cni-podman0 インタフェースを作れないなどのエラーでコンテナが動かない。

priviledged モードによるコンテナ実行

https://developers.redhat.com/e-books/podman-action
https://www.redhat.com/en/blog/podman-inside-container

によれば、 security-opt ではなくて --privileged モードで動かすと良いとある。

$ docker run -it --privileged --rm [service-container] bash
[root@xxxxxxxx /]# dnf install -y podman
[root@xxxxxxxx /]# podman run hello-world
Resolved "hello-world" as an alias (/etc/containers/registries.conf.d/000-shortnames.conf)
Trying to pull quay.io/podman/hello:latest...
Getting image source signatures
Copying blob 81df7ff16254 done   | 
Copying config 5dd467fce5 done   | 
Writing manifest to image destination
!... Hello Podman World ...!

         .--"--.           
       / -     - \         
      / (O)   (O) \        
   ~~~| -=(,Y,)=- |         
    .---. /`  \   |~~      
 ~/  o  o \~~~~.----. ~~   
  | =(X)= |~  / (O (O) \   
   ~~~~~~~  ~| =(Y_)=-  |   
  ~~~~    ~~~|   U      |~~ 

Project:   https://github.com/containers/podman
Website:   https://podman.io
Desktop:   https://podman-desktop.io
Documents: https://docs.podman.io
YouTube:   https://youtube.com/@Podman
X/Twitter: @Podman_io
Mastodon:  @Podman_io@fosstodon.org

"/" のマウント警告も出ず、実行できた。 アザラシかわゆす。 (´ω`っ )3

ユーザ権限での実行確認

ユーザ権限でも実行できるか確認。

[root@xxxxxxx /]# adduser testuser

としてユーザ追加し、ユーザ名指定でコンテナに入り、コンテナ実行。

[testuser@xxxxxxx /]$ podman run hello-world
!... Hello Podman World ...!

         .--"--.           
       / -     - \         
      / (O)   (O) \        
   ~~~| -=(,Y,)=- |         
    .---. /`  \   |~~      
 ~/  o  o \~~~~.----. ~~   
  | =(X)= |~  / (O (O) \   
   ~~~~~~~  ~| =(Y_)=-  |   
  ~~~~    ~~~|   U      |~~ 

Project:   https://github.com/containers/podman
Website:   https://podman.io
Desktop:   https://podman-desktop.io
Documents: https://docs.podman.io
YouTube:   https://youtube.com/@Podman
X/Twitter: @Podman_io
Mastodon:  @Podman_io@fosstodon.org

警告も出ず実行できた。

イメージビルド

ADユーザのホームディレクトリ領域が NFSマウントされている場合のために、コンテナ保存先をホームディレクトリ以外の場所に設定する。

storage.conf:

[storage]

rootless_storage_path = "/var/tmp/$USER"

ADユーザのuid, gid に対して subuid, subgid 設定をコンテナにも反映。
subuid,subgidについては rootless 用プロセス設定 を参照。

ADユーザで実行できるようwinbindを入れておく。

...
RUN dnf update -y && \
    dnf install -y \
        ...
        authselect samba-winbind-clients \
        podman 

## AD設定
ENV SECRET_AD_USER=""
ENV SECRET_AD_PASSWD=""

COPY smb.conf /etc/samba
RUN authselect select winbind --force

## podman設定
COPY ./storage.conf /etc/containers/storage.conf
COPY ./subuid /etc/subuid
COPY ./subgid /etc/subgid

## サービス実行用スクリプト
COPY ./run.sh /usr/local/bin/
RUN chmod  +x /usr/local/bin/run.sh

CMD ["/usr/local/bin/run.sh"]

最後のサービス実行用スクリプトには AD認証できるよう winbindd 実行する。

run.sh:

#!/bin/sh

### AD参加
net ads join -U "${SECRET_AD_USER}%${SECRET_AD_PASSWD}"
winbindd -D

### サービスプログラム実行
xxxx

K8s サービスを privileged モードで動かす

privileged モードで pod を動かすには spec.containers.securityContext.privileged=true にすればよい。

マニフェストに以下を追記して適用。

---
apiVersion: v1
kind: Secret
metadata:
  name: my-service-sercret
type: Opaque
data:
  SECRET_AD_USER: *************
  SECRET_AD_PASSWD: ***********
---
apiVersion: apps/v1
kind: StatefulSet
spec:
  template:
    spec:
      containers:
      - name: my-service
        securityContext:
          privileged: true

        env:
        - name: SECRET_AD_USER
          valueFrom:
            secretKeyRef:
              name: my-service-sercret
              key: SECRET_AD_USER
        - name: SECRET_AD_PASSWD
          valueFrom:
            secretKeyRef:
              name: my-service-sercret
              key: SECRET_AD_PASSWD
...

AD参加時のユーザ・パスワードを Secret リソースとして登録し、環境変数 SECRET_AD_USER, SECRET_AD_PASSWD でコンテナに渡すようにしている。

上記イメージに更新してpod起動しなおすことで、ADユーザでコンテナ実行ができる。

### 更新したイメージで起動しなおすよう既存 pod を停止 → StatefulSet により自動再起動
$ kubectl delete pods [service-continer]
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?