🐳

ホストマシンを再起動すると、Dockerコンテナに対するSSH_AUTH_SOCKのマウントがうまくいかない

2024/08/02に公開

事象

一度コンテナを立ち上げ、そのあとホストマシン(Ubuntu)を再起動。
再起動後に再びコンテナを立ち上げようとするとマウントできない旨のエラーが出る。

Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error mounting "/tmp/ssh-ZyloNEwSAswN/agent.1551" to rootfs at "/tmp/ssh-ZyloNEwSAswN/agent.1551": mount /tmp/ssh-ZyloNEwSAswN/agent.1551:/tmp/ssh-ZyloNEwSAswN/agent.1551 (via /proc/self/fd/7), flags: 0x5000: not a directory: unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type

環境

  • Ubuntu24.04 (WSL)
  • Docker (version 27.1.1)
  • devcontainer cli (version 0.66.0)

前提

Ubuntuで ssh-agent を起動するとソケットは /tmp/ssh-xxxxx/agent.xxx に配置される。 この場所は echo $SSH_AUTH_SOCK で確認できる。

docker compose を用いてコンテナ上を立ち上げる際、Ubuntuの ssh-agent を引き継ぐには以下のようにenvとvolumesを設定する(ことがネットで散見された)。

docker-compose.yml

services:
  app:
    build:
      context: .
      dockerfile: ./Dockerfile
    environment:
      - SSH_AUTH_SOCK=$SSH_AUTH_SOCK
    volumes:
      - $SSH_AUTH_SOCK:$SSH_AUTH_SOCK
    tty: true

私は実際には docker compose を使っておらず、devcontainer cli を使用している。
.devcontainer/devcontainer.json

{
        "name": "Ubuntu",
        "dockerComposeFile": "docker-compose.yml",
        "service": "app"
}

実行コマンド。(docker compose up と docker compose execと同じようなコマンド)

$ devcontainer up  --workspace-folder .
$ devcontainer exec --workspace-folder .  bash

原因

Ubuntu再起動後に ssh-agent を起動すると、前回とは異なる位置にソケットが配置される。(/tmp/ssh-xxxxx/agent.xxxという形式なので)

そしてdocker-compose.ymlに記載したvolumesはビルド時に固定されるため、あとから変えることはできない。

そのためUbuntu再起動後にコンテナを立ち上げようとすると、(ビルド時に固定した)再起動前のソケットをマウントしようと試みて失敗する。

対処法

鍵情報をコンテナの ~/.ssh/ に書き込んだり、コンテナを作り直したりすることで解決はできるらしい。

別の方法はないかと探してみたところ、どうやら ssh-agent のオプションでソケットの配置場所を設定するオプションがあるらしい。

man ssh-agentの結果

       -a bind_address
               Bind   the   agent    to    the    Unix-domain    socket    bind_address.     The    default    is
               $TMPDIR/ssh-XXXXXXXXXX/agent.<ppid>.

これを使えばソケットの配置場所が固定されるので問題が解決できる。

具体的には .bash_profile に下のように記載すれば良い。

$ cat ~/.bash_profile
if [ -z "$SSH_AUTH_SOCK" ]; then
    # Check for a currently running instance of the agent
    RUNNING_AGENT="`ps -ax | grep 'ssh-agent -s' | grep -v grep | wc -l | tr -d '[:space:]'`"
    if [ "$RUNNING_AGENT" = "0" ]; then
         mkdir -p /tmp/ssh
         # Launch a new instance of the agent
         ssh-agent -s -a /tmp/ssh/agent.sock &> $HOME/.ssh/ssh-agent
    fi
    eval `cat $HOME/.ssh/ssh-agent` >& /dev/null
fi

if [ -f ~/.bashrc ] ; then
    . ~/.bashrc
fi

Discussion