DockerのJenkinsコンテナからSMB/CIFSのNASをマウントする
これは2023-04-16に書いた古い記事です。内容が古いですがアーカイブとして残しておきます。
はじめに
ふと思い立ち、自宅のWindows10マシンのDocker Desktop on Windows上にJenkinsのコンテナを立てた際に、コンテナ側からNAS上のSMB/CIFS共有のドライブをマウントしようとして数時間ハマった。
この記事は基本的には先人が書き留めた情報をインターネットから拾い集めパッチワークしたものに過ぎないが、いずれ誰かの役に立つかも知れないので、ここにメモを残しておこうと思う。やりたい事は以下の通り。
- Docker Desktop on WindowsでJenkinsのコンテナを立てる。
- Jenkinsで自作のPythonスクリプトを定期実行する。
- PythonスクリプトではNAS上のファイルを操作する。NAS はSynologyのDiskStation DS418である。
docker-compose.yml初期版
version: '3'
services:
jenkins:
container_name: jenkins
image: jenkins/jenkins:latest
ports:
- 8080:8080
volumes:
- type: bind
source: ./jenkins_home
target: /var/jenkins_home
restart: always
Webで適当に検索して、上記の通りdocker-compose.ymlファイルを作成した。
docker-compose.ymlにこれを記述した後、PowerShellのコンソールからdocker-compose upのコマンドを打てば、それだけでサーバーが起動する。後は手元のブラウザからlocalhost:8080に接続すれば、Jenkinsが起動している事が確認できる。実に簡単だ。便利な時代になった。
- Docker Desktop on Windowsでは他にも色々なサーバーを立てているが、ポート8080は空いていたので
ports:の設定は変更していない。 - Windowsの再起動後にコンテナが自動で立ち上がるよう、
restart: alwaysを指定している。 - Jenkinsの初期画面等の情報はWeb上に溢れているので、ここでは割愛する。
docker-compose.ymlの変更
やりたいことを実現するため、docker-compose.ymlに手を加えてゆく。
タイムゾーンを変更する
environment:
# タイムゾーンを設定する
- JAVA_OPTS=-Duser.timezone=Asia/Tokyo
デフォルトのタイムゾーンはUTCになっている。
タイムゾーンがUTCのままだと使用する際に直感的に分かりにくいと思ったので、enviroment:にJAVA_OPTS=-Duser.timezone=Asia/Tokyoを指定して、タイムゾーンを JST に変更しておいた。設定の際はこの記事を参考にした。
Jenkinsコンテナにpython3をインストールする
# sudoがないのでrootで始める
user: root
# python3をインストールした後にjenkins.shで起動する
command: >
bash -c "
apt-get update &&
apt-get install --no-install-recommends -y python3 &&
apt-get install --no-install-recommends -y pip &&
/usr/local/bin/jenkins.sh"
image: jenkins/jenkins:latestで指定しているJenkins公式のイメージにはPythonがインストールされていない。必要ないからだ。command:にて指定する形で愚直にpython3をインストールしようと思ったが、ややハマった。
最初にapt-get updateを実行し、次にapt-get installでpython3とpipを順にインストールし、最後は/usr/local/bin/jenkins.shのシェルスクリプトを叩いてJenkinsを起動している。この最終系に辿り着くに辺り、ハマった点を以下に列挙する。
このコンテナにはsudoがない
jenkins | bash: line 1: sudo: command not found
Jenkins公式のイメージは最小限の構成であるためか、sudoコマンドが入っていなかったので、sudo apt-get updateが通らない。
最小限の構成のコンテナには、sudoがないのが普通なのだろうか?
sudoがないならrootでやる
jenkins | Reading package lists…
jenkins | E: List directory /var/lib/apt/lists/partial is missing. - Acquire (13: Permission denied)
rootでないと権限が足りず死ぬ。この記事を参考にして、user: rootを指定した。
command:は追加ではなく書き換え
前述の通り、やりたいのはpython3とpipのインストール後にJenkinsを起動することである。
だが、最後の/usr/local/bin/jenkins.shを叩かないと画像のような状態になってしまう。command:の指定によりデフォルトのコマンドの書き換えが行われるので、肝心のjenkins.shを叩かないと、python3とpipのインストールだけで終わった状態になってしまうのである。原因の調査、対応のヒントとしてはこの記事がとても参考になった。
「じゃあcommand:に何も指定していない場合に実行される、Jenkinsを起動するデフォルトのコマンドって何だよ?!」となったのだが、Webで調べてもイマイチ分からなかった。そのため自分で色々調べたが、多分jenkins.shで良い筈だ。
docker-compose.yml途中版
version: '3'
services:
jenkins:
container_name: jenkins
image: jenkins/jenkins:latest
ports:
- 8080:8080
volumes:
- type: bind
source: ./jenkins_home
target: /var/jenkins_home
restart: always
environment:
# タイムゾーンを設定する
- JAVA_OPTS=-Duser.timezone=Asia/Tokyo
# sudoがないのでrootで始める
user: root
# python3をインストールした後にjenkins.shで起動する
command: >
bash -c "
apt-get update &&
apt-get install --no-install-recommends -y python3 &&
apt-get install --no-install-recommends -y pip &&
/usr/local/bin/jenkins.sh"
色々試して、この時点でdocker-compose.ymlは上記の通りとなった。Jenkinsのジョブでpython3が動く状態である。
絶対パスでマウントするには
volumes:
# ローカルのスクリプト配置場所
- type: bind
source: /c/dezikomoe_python
target: /var/dezikomoe_python
read_only: true
実行したいPythonのコードはホストマシン上に存在するため、Jenkinsコンテナからそれが見えるようにマウントする必要がある。
Webでサンプルを調べてみたのだが、volumes:の指定は相対パスで記述されているか、絶対パスで指定する場合でも/開始のものばかりだった。では和尚様、Windows環境にてドライブレターから絶対パスを指定する場合はどう書くのですか?
内容は少し古いがこの記事が参考になった。要するに c:\dezikomoe_pythonではなく/c/dezikomoe_pythonで記述すればOK。
なお、Jenkinsコンテナ側からPythonスクリプトを変更することはないので、念のためread_only: trueを指定している。
NASをマウントする
やっとこの記事の本題に辿り着いた。
ここからコンテナからNASにアクセスできるように設定を入れていく。当初はこの記事を見て、余裕そうだと思っていたのだが……
SMB/CIFSのNASをマウントする→失敗
volumes:
# 処理対象ファイル
- ds418_01_photo:/var/photo:ro
volumes:
ds418_01_photo:
driver_opts:
type: cifs
device: //192.168.11.50/photo
o: username=●●●,password=■■■
device:で接続先のNASのIPアドレスを指定して、o:で認証情報を指定している。
operation not supported
ERROR: for jenkins Cannot start service jenkins: error while mounting volume '/var/lib/docker/volumes/jenkins_ds418_01_photo/_data': failed to mount local volume: mount
//192.168.11.50/photo:/var/lib/docker/volumes/jenkins_ds418_01_photo/_data, data: username=●●●,password=■■■: operation not supported
いきなりエラーを吐いて死ぬ。想定外の operation not supported のエラーが出て怒られてしまった。うーむ……。Stack Overflowでも似たようなやり取りを見付けられたが、結論としては、ほぼ最初の記事の内容と変わらずであった。
"docker SMB operation not supported"等で検索してみるも、目ぼしい情報は見付けられなかった。困った。
cifs-utilsでマウントできるか?
command: >
bash -c "
apt-get update &&
apt-get install --no-install-recommends -y cifs-utils &&
mkdir /var/photo &&
mount -t cifs -o username=●●●,password=■■■ //192.168.11.50/photo /var/photo"
この時点で既に02:00を回っており寝てしまいたかったが、土曜日だったので問題の切り分けに進んだ。
operation not supported以外のもう少し詳細なエラー情報が欲しい。そもそも通常の手段でマウントできるのか?を調べてみよう。cifs-utilsを使うためにcommand:の指定を一時的に上記のように変えて動かしてみた。
cifs-utilsでもエラー
jenkins | Unable to apply new capability set.
cifs-utilsをインストールしてmountを実行する。すると、上記のエラーが出た。
Unable to apply new capability set
jenkins | mount error(95): Operation not supported
jenkins | Refer to the mount.cifs(8) manual page (e.g. man mount.cifs) and kernel log messages (dmesg)
Unable to apply new capability setでGoogle検索をすると、この記事がヒットした。
記事に従ってprivileged: trueを追加して動かしてみると、またエラー内容が変わった。先程出ていたOperation not supportedのメッセージは、どうやらここから出ているようだ。エラーの解決まで後少しの所まで来ている気がする。もう少し頑張ろう。
mount error(95): Operation not supported
mount error(95): Operation not supportedを丸ごと検索すると、今度はこの記事がヒットした。SMBのバージョンの問題??
DS418の設定を確認すると、画像の通りSMB1・SMB2のみのサポートになっていた。ビンゴだ!
docker-compose.yml完成版
version: '3'
services:
jenkins:
container_name: jenkins
image: jenkins/jenkins:latest
ports:
- 8080:8080
volumes:
- type: bind
source: ./jenkins_home
target: /var/jenkins_home
# ローカルのスクリプト配置場所
- type: bind
source: /c/dezikomoe_python
target: /var/dezikomoe_python
read_only: true
# 処理対象ファイル
- ds418_01_photo:/var/photo:ro
restart: always
environment:
# タイムゾーンを設定する
- JAVA_OPTS=-Duser.timezone=Asia/Tokyo
# sudoがないのでrootで始める
user: root
# python3をインストールした後にjenkins.shで起動する
command: >
bash -c "
apt-get update &&
apt-get install --no-install-recommends -y python3 &&
apt-get install --no-install-recommends -y pip &&
/usr/local/bin/jenkins.sh"
volumes:
ds418_01_photo:
driver_opts:
type: cifs
device: //DS418_01/photo
o: username=●●●,password=■■■,addr=DS418_01,vers=2.0
完成版のdocker-compose.ymlが上記である。
o:にてvers=2.0を明示的に指定する事で、NAS側のSMBのバージョンであるSMB2と合せている。エラーの根本的原因はこれで解消した。
また、当初は IP アドレスを指定していたが addr=DS418_01と組み合わせる事でホスト名で指定をしている。

