0.はじめに(この記事を書いた理由)
-
「なぜ今Subversionなんだ」とお思いの読者もいるかと思うが、
下記のような状況によりDocker環境でSubversionを構築する必要がある人もいるかもしれない。- SI企業に勤めており、CI/CDを始めたいけど現場のエンジニアがGitの使い方を知らない
- ドキュメントもMarkdownではなくExcelで作ったため、Gitで管理するのには不向き(LFSを使えばいいとかそういうツッコミはありそうだが…)
-
一応、SubversionをDockerイメージにしている例としては、elleFlorio/svn-dockerが存在する。こちらは
alpine
ベースで軽量だが、サードパーティ製のイメージであり、そのままDockerHubからPullして業務で使うことは開発基準的に難しい場合も多いと思う。 -
そのため、SubversionのDockerイメージを自作する必要があるエンジニアもやはりいるかと思った。
-
上記のような境遇のエンジニアの方に、本記事が少しでも助けになればと思い、この記事を執筆した。
0-1.目標成果物の確認
次のような要件を含むDockerのコンテナイメージを作成する
-
svn://
のプロトコルだけでなく、http://
、https://
のプロトコルでも操作可能にしたい
(※)セキュリティ的な要件により、通信を暗号化してhttps
のプロトコルでやり取りしてほしいと要求があった時のために - そのために、Httpdを含んだSubversionコンテナのイメージを作成する
- なお、注意いただきたいのだが、HttpdコンテナとSubversionコンテナを分けて構築することは、おそらく不可能かと思う。Nginxなどの場合にはNginxコンテナとそこからリバースプロキシされるコンテナを分けて構築し、nginx.confでリバースプロキシの設定を行ったりするのだが、Httpdの場合にはそのようなアーキテクチャにはできないと思われるので注意してほしい。
0-2.作成対象物一覧
今回の作成対象は下記になる
作成対象物 | 概要 |
---|---|
Dockerfile | 今回のメインの開発物になる。Dockerのコンテナイメージをビルドするのに必要だが、特に説明は要らないだろう |
apache/run.sh | httpd(Apache)をフォアグラウンドで起動するシェルスクリプト |
subversion/run.sh | svnserve(svnのプロトコルでリポジトリにアクセス)のプロセスを起動する為のシェルスクリプト |
svn.conf | Subversionの設定ファイル。LDAP認証情報やレポジトリのPathなどを定義する |
localuser.list | Subversionのコンテナ内でのみ有効なローカルユーザーの情報を定義したテキストファイル |
subversion-access-control | どのリポジトリにどのユーザーがRead / Write権限を持つのか定義したテキストファイル。svn.confの中で本ファイルのPathを指定する必要がある |
docker-compose.yaml | コンテナを立ち上げる際に必要。ここまで記載しようか迷ったが、永続ボリュームとしてマウントすべきPathを定義する為、一応記載しておこうと思う |
上記のファイルを次のように配置しておくことを前提として開発を進める。
any_dir/
├ Dockerfile
├ apache/
│ └ run.sh
├ subversion/
│ └ run.sh
├ svn.conf
├ localuser.list
├ subversion-access-control
└ docker-compose.yaml
それでは、実際の開発に取り掛かろう
1.Dockerfileの作成
- Subversionには、デフォルトで利用可能なプロトコルが1つ存在する(svn://)
- 今回は通信の暗号化の要件に備え、上記のプロトコルに加えhttp/httpsでも通信できるようなコンテナイメージをビルドする
1-1.ベースとなるイメージを指定
# http/httpsのプロトコルで通信を行うため、Subversionの他にApache-Httpdが含まれるコンテナイメージを構築する。
# 正確には、Apache-HttpdのコンテナにSubversionをInstallするのだが、
# "httpd"という名称でApacheから公式イメージが提供されているのでそれを使用する
FROM httpd:latest
1-2.SubversionとSubversion - Apacheの連携を行うためのモジュールのInstall
このhttpdはDebianをベースとしたイメージであるため、apt
またはapt-get
を用いたInstall方法になる。
尚言うまでもないがCentOSなどのRHEL系をベースに使用する場合には下記の点で差異が出るため注意すること
- (RHEL系の場合)
yum install ...
コマンドになる - (RHEL系の場合)
libapache2-mod-svn
ではなくmod_dav_svn
となる
参考:【SVN】サーバにSVNを導入しよう
# SubversionのInstall
# libapache2-mod-svn(SVNとApacheの連携を行い、複数ユーザーがApache経由でリポジトリとやり取りするためのモジュール)のInstall
# 正直、設定ファイルが格納されたディレクトリを永続化するのでsudoとvimは不要な気もする
RUN apt update && apt install -y \
libapache2-mod-svn subversion-tools sudo vim \
subversion --no-install-recommends &&\
apt clean
1-3.Subversionのリポジトリ用のディレクトリを作成する
尚、このディレクトリパスは後続でsvn.conf
内に指定する必要がある
# リポジトリ用のディレクトリを作成
RUN mkdir -p /home/svn/repos &&\
mkdir -p /run/apache2/ &&\
mkdir -p /etc/subversion &&\
touch /etc/subversion/passwd
1-4.Subversionコンテナ内でのみ有効なローカルユーザーを作成しておく
これはlocaluser.list
というテキストファイルを用意し、そのテキストファイルを後続で作成するsvn.conf
で読み込むように設定を行う
# LDAP認証ができない場合に備え、ローカルユーザーでもアクセスできるようにユーザー名+パスワードのファイルを作成し、初期ユーザーを登録
# 初期ユーザーはID:admin, Pass:admin、パスワードはMD5形式で保存されている
COPY localuser.list /home/svn/localuser.list
1-5.コンテナ立ち上げ時に実行させるシェルスクリプトをCOPYする
下記の2つのシェルスクリプトをコピーするのだが、スクリプトの内容は後述
- httpd(Apache)をフォアグラウンドで起動するシェルスクリプト
- svnserve(svnのプロトコルでリポジトリにアクセス)のプロセスを起動する為のシェルスクリプト
# httpd(Apache)をフォアグラウンドで起動するシェルスクリプトを/etc/services.d/apache/配下にコピー
COPY apache/ /etc/services.d/apache/
# svnserve(svnのプロトコルでリポジトリにアクセス)のプロセスを起動する為のシェルスクリプトを/etc/services.d/subversion/配下にコピー
COPY subversion/ /etc/services.d/subversion/
1-6.ユーザーごとのアクセスコントロールを定義するファイルを作成
ローカルに定義するファイルを置いて、ビルド時にコンテナイメージの中にCOPYする
このファイルは永続ボリュームにマウントし、後から編集できるようにしておくこと
COPY subversion-access-control /etc/subversion/subversion-access-control
RUN chmod a+w /etc/subversion/* && chmod a+w /home/svn
1-7.httpでアクセスするために必要なモジュールをコンテナ内部でコピーする
httpdイメージの/usr/lib/apache2/modules/
配下にhttp/httpsでSubversionにアクセスするために必要なモジュールが存在するが、そのままではApacheのプロセスがこのモジュールを読み込めない。
そこで、cp
コマンドを用いて必要モジュールを/usr/local/apache2/modules/
配下にコピーする。
# WebDav(httpでアクセスする)のために必要なモジュールをapacheのプロセスが参照できるようにコピーする
RUN cp /usr/lib/apache2/modules/mod_dav.so /usr/local/apache2/modules/ &&\
cp /usr/lib/apache2/modules/mod_dav_svn.so /usr/local/apache2/modules/ &&\
cp /usr/lib/apache2/modules/mod_authz_svn.so /usr/local/apache2/modules/
また、httpd.conf
も編集が必要である。編集内容は下記の2点
- (ポートをデフォルトの80番からずらす場合)デフォルトでListenしているポートを書き換える
(※)この場合、Dockerfile
のEXPOSE
で公開するポートも8080にする必要があるため注意すること - Subversionの設定ファイルである
svn.conf
をコピーするので、httpd.conf
から読み込めるようにする
httpd.conf
は/usr/local/apache2/conf/httpd.conf
のパスに存在するため、下記のコマンドで取り出すことができる。
$ docker run --rm httpd:latest cat /usr/local/apache2/conf/httpd.conf > httpd.conf
もちろんこれを直接編集したうえでDockerfile
上でCOPY
してもよいが、今後のhttpd
のベースイメージのバージョンアップに伴いhttpd.conf
の内容に変更が発生する可能性を考えると、Dockerfile
内で直接行を編集する方が保守性が高い。
# WebDav(httpでアクセスする)の設定ファイルをコピーし、httpd.confから読み込むよう設定する
RUN sed -i s/'Listen 80'/'#Listen 80'/ /usr/local/apache2/conf/httpd.conf &&\ # 80番ポートをListenしている行をコメントアウト
sed -i -e '/#Listen 80$/a Listen 8080' /usr/local/apache2/conf/httpd.conf &&\ # コメントアウトした行の直後に8080番ポートをListenする設定を追加
echo 'Include conf/extra/svn.conf' >> /usr/local/apache2/conf/httpd.conf
COPY svn.conf /usr/local/apache2/conf/extra/
結果として、httpd.conf
が次のようになればよい
# (中略)
#Listen 12.34.56.78:80
#Listen 80
Listen 8080
...
# (中略)
...
</IfModule>
Include conf/extra/svn.conf
1-8.コンテナの実行ユーザーの作成及び権限付与
root
ユーザーでコンテナを起動するのはセキュリティ的にあまりよろしくないのでこのコンテナを実行する用のユーザーを作成しておく
何かあった時のために、このユーザーにsudo
権限などを付加してしまっているが、不要な場合は削除してほしい
# 実行ユーザーを作成するため、このDockerfile内で有効な環境変数を設定
ARG USERNAME=subversion
ARG GROUPNAME=subversion
ARG UID=999
ARG GID=999
# 実行ユーザーの作成
RUN groupadd -g $GID $GROUPNAME && \
useradd -ml -s /bin/bash -u $UID -g $GID $USERNAME &&\
echo "${USERNAME}:${USERNAME}" | sudo chpasswd
# 実行ユーザーでvi等で編集できるようにsudo権限をつけておく
RUN echo "Defaults visiblepw" >> /etc/sudoers
RUN echo "${USERNAME} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
# ディレクトリ権限の変更
RUN chown -R $UID:$GID /etc/services.d/apache &&\
chown -R $UID:$GID /etc/services.d/subversion &&\
chown -R $UID:$GID /etc/subversion &&\
chown -R $UID:$GID /home/svn &&\
chown -R $UID:$GID /usr/local/apache2
1-9.実行ユーザーを切り替え、ポートをExpose
ちなみにExposeするポートは下記の3つである。
- 3690
svn://
のプロトコルで通信を行うポート - 8080
http://
のプロトコルで通信を行うポート - 443
https://
のプロトコルで通信を行うポート
# 実行ユーザーの切り替え
USER $USERNAME
# http, https, svnのプロトコルでアクセスするためのポートをExpose
EXPOSE 3690 8080 443
1-10.Dockerfileの完成形
FROM httpd:latest
RUN apt update && apt install -y \
libapache2-mod-svn subversion-tools sudo vim \
subversion --no-install-recommends &&\
apt clean
RUN mkdir -p /home/svn/repos &&\
mkdir -p /run/apache2/ &&\
mkdir -p /etc/subversion &&\
touch /etc/subversion/passwd
COPY localuser.list /home/svn/localuser.list
COPY apache/ /etc/services.d/apache/
COPY subversion/ /etc/services.d/subversion/
COPY subversion-access-control /etc/subversion/subversion-access-control
RUN chmod a+w /etc/subversion/* && chmod a+w /home/svn
RUN cp /usr/lib/apache2/modules/mod_dav.so /usr/local/apache2/modules/ &&\
cp /usr/lib/apache2/modules/mod_dav_svn.so /usr/local/apache2/modules/ &&\
cp /usr/lib/apache2/modules/mod_authz_svn.so /usr/local/apache2/modules/
RUN sed -i s/'Listen 80'/'#Listen 80'/ /usr/local/apache2/conf/httpd.conf &&\
sed -i -e '/#Listen 80$/a Listen 8080' /usr/local/apache2/conf/httpd.conf &&\
echo 'Include conf/extra/svn.conf' >> /usr/local/apache2/conf/httpd.conf
COPY svn.conf /usr/local/apache2/conf/extra/
ARG USERNAME=subversion
ARG GROUPNAME=subversion
ARG UID=999
ARG GID=999
RUN groupadd -g $GID $GROUPNAME && \
useradd -ml -s /bin/bash -u $UID -g $GID $USERNAME &&\
echo "${USERNAME}:${USERNAME}" | sudo chpasswd
RUN echo "Defaults visiblepw" >> /etc/sudoers
RUN echo "${USERNAME} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
RUN chown -R $UID:$GID /etc/services.d/apache &&\
chown -R $UID:$GID /etc/services.d/subversion &&\
chown -R $UID:$GID /etc/subversion &&\
chown -R $UID:$GID /home/svn &&\
chown -R $UID:$GID /usr/local/apache2
USER $USERNAME
EXPOSE 3690 8080 443
2.apache/run.shの作成
httpd(Apache)をフォアグラウンドで起動するシェルスクリプトは下記の通り
これは1-5の手順でDockerfile
でコンテナイメージの中にCOPY
を行う
#!/bin/bash
# 'already pid is running'というエラーを避けるために、pidファイルを削除
rm -f /run/apache2/httpd.pid
# httpd(Apache)をフォアグラウンドで起動
exec /etc/init.d/httpd -DFOREGROUND;
3.subversion/run.shの作成
svnserve(svnのプロトコルでリポジトリにアクセス)のプロセスを起動する為のシェルスクリプトは下記の通り
このスクリプトは1-5の手順においてDockerfile
でコンテナイメージの中にCOPY
を行う
#!/bin/bash
exec /usr/bin/svnserve -d --foreground -r /home/svn/repos --listen-port 3690;
4.svn.conf
このファイルの中で次の設定を行う
- Subversionの設定(リポジトリのパスなど)
- LDAPの設定
LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
LoadModule ldap_module modules/mod_ldap.so
LoadModule dav_module modules/mod_dav.so
LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so
# Locationタグで指定されたパスがリポジトリのURLになる
# この場合は/svn/reposと記載したのでリポジトリのURLはhttp://hostname/svn/reposとなる
<Location /svn/repos>
DAV svn # お決まりの文言
SVNParentPath /home/svn/repos # リポジトリがコンテナ内のどのフォルダに作られるかを指定する
SVNListParentPath On # ブラウザでリポジトリにアクセスした際、リポジトリ配下をリスト表示させるかを指定
AuthType Basic # Basic認証を指定
AuthName "Subversion repository" # 認証画面に表示される認証名
AuthBasicProvider file ldap
AuthUserFile /home/svn/localuser.list # ユーザー名とパスワードが記載されているファイル名を指定
Require valid-user # アクセスを許可するユーザを指定。「valid-user」はパスワードファイルに含まれているすべてのユーザに許可することを意味する
Order Allow,Deny
Allow from All
# 以下はLDAPの設定
AuthLDAPBindAuthoritative on
AuthLDAPBindDN administrator@example.com
AuthLDAPUrl "ldap://ad.example.com:389/dc=example,dc=com,?sAMAccountName?sub?(objectClass=*)"
AuthLDAPBindPassword "admin-password"
Require ldap-attribute objectClass=person
AuthzSVNAccessFile /etc/subversion/subversion-access-control
</Location>
尚、この辺りの設定は下記のサイトを参考にさせていただいた。この場をお借りして感謝を申し上げる
5.localuser.list
- LDAPサーバーと疎通がとれていなくても最低限の動作確認はできるよう、初期ユーザーを用意しておくのが良いかと思う
- Subversionコンテナをビルドし、docker-composeで立ち上げた後、下記のようにコンテナ内に入って
htpasswd
コマンドを実行することでファイルの追加、内容の追記ができる - こうして初期ユーザーのみ作成された
localuser.list
ファイルをローカルにdocker cp
でもしておいて、コンテナイメージを再度ビルドするときにイメージ内にCOPY
してしまえば、次回から初期設定の手間が省けて楽かと思う
# 例えば一度Subversionのコンテナをビルドして、立ち上げてしまう
$ docker build -t subversion:latest .
$ docker-compose up -d
...
# で、立ち上げたコンテナの中に入ってhtpasswdコマンドを実行して、ユーザーとパスワードを作成しておく
$ docker exec -it subversion bash
subversion:$ cd /home/svn
subversion:$ htpasswd -c -m localuser.list admin
New password:
Re-type new password:
Adding password for user admin
subversion:$ htpasswd -m users admin2
New password:
Re-type new password:
Adding password for user admin2
subversion:$ exit
# この後に先ほど作成したlocaluser.listをホストOSにコピーしてしまう
$ docker cp subversion:/home/svn/localuser.list .
長くなってしまったが、上記におけるhtpasswd
の基本的なオプションは下記の通り
オプション | 説明 |
---|---|
-c | 新たにユーザーリストのファイルを生成する (既に存在するリストに追記する場合には-cオプションを外す) |
-m | パスワードをMD5形式で記載する |
この辺りのオプションは下記の記事が参照になるかと思う
6.subversion-access-control
どのリポジトリにどのユーザーがRead / Write権限を持つのか定義したテキストファイルである
[groups]
[/]
* = rw
この場合、ルートディレクトリ([/]
)配下に対して、すべてのユーザー(*
)が参照・編集権限を持つ(rw
)ようになる
この辺りの設定に関しては次の記事に詳しくまとめられているので参考にしてほしい
7.docker-compose.yaml
言うまでもないが、Subversionコンテナの実行ユーザーはUID=999
, GID=999
で作成しているため、
ホストOSにマウントするディレクトリの所有者もchown -R 999:999 ...
としておくのが望ましい
コンテナ名やマウントするディレクトリパスは各自の環境に合わせて適宜変更してほしい
version: '3.0'
services:
subversion:
image: subversion:latest
container_name: subversion
restart: always
ports:
- "8080:8080"
- "3690:3690"
volumes:
- apache2_conf:/usr/local/apache2/conf # httpd.confおよびsvn.confの編集の為に必要
- subversion_access:/etc/subversion # subversion-access-controlの編集の為に必要
- svn_home:/home/svn # ローカルユーザー及びレポジトリの永続化の為に必要
volumes:
apache2_conf:
driver_opts:
type: none
device: /vol/subversion/apache2_conf
o: bind
subversion_access:
driver_opts:
type: none
device: /vol/subversion/subversion_access
o: bind
svn_home:
driver_opts:
type: none
device: /vol/subversion/svn_home
o: bind
8.コンテナイメージのビルド、立ち上げ、動作確認
ここまで、筆者がとても苦労したため同じ苦労を他のエンジニアに味合わせまいとかなり細かく記事を書いてしまった。
もう少しである。最後までお付き合いいただきたい。
8-1.コンテナイメージのビルド、立ち上げ
$ docker build -t subversion:latest .
...
$ docker-compose up -d
...
この段階で、http://localhost:8080
にアクセスして次のようにApacheの画面が出れば起動成功である。
8-2.レポジトリの作成
# Subversionコンテナの中に入って操作を行う
$ docker exec -it subversion bash
# /home/svn/repos(svn.confファイルのSVNParentPathで設定した値)のパスに移動
subversion$ cd /home/svn/repos
# レポジトリの作成。testrepoというディレクトリが存在しない場合には自動で作成される
subversion$ svnadmin create testrepo
subversion$ ls
testrepo
# レポジトリの設定ファイルなどもsvnadmin createコマンドで自動作成されることが分かる
subversion$ ls testrepo
README.txt conf db format hooks locks
この段階でhttp://localhost:8080/svn/repos
にアクセスして次のようにレポジトリが作成されていることを確認してほしい。
あとはTortoiseSVNを使ってアクセスするなりLDAPの設定を変更するなり自由に運用してほしい。
9.Git Repository
一応、ここまでのファイルはGitHubにアップしているので参考になれば幸いである。
GitHub : Subversion-Docker
お疲れ様でした。