7
8

More than 1 year has passed since last update.

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コンテナのイメージを作成する
    image.png
  • なお、注意いただきたいのだが、HttpdコンテナとSubversionコンテナを分けて構築することは、おそらく不可能かと思う。Nginxなどの場合にはNginxコンテナとそこからリバースプロキシされるコンテナを分けて構築し、nginx.confでリバースプロキシの設定を行ったりするのだが、Httpdの場合にはそのようなアーキテクチャにはできないと思われるので注意してほしい。
    image.png

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.ベースとなるイメージを指定

Dockerfile
# 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系をベースに使用する場合には下記の点で差異が出るため注意すること

Dockerfile
# 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内に指定する必要がある

Dockerfile
# リポジトリ用のディレクトリを作成
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で読み込むように設定を行う

Dockerfile
# LDAP認証ができない場合に備え、ローカルユーザーでもアクセスできるようにユーザー名+パスワードのファイルを作成し、初期ユーザーを登録
# 初期ユーザーはID:admin, Pass:admin、パスワードはMD5形式で保存されている
COPY localuser.list /home/svn/localuser.list

1-5.コンテナ立ち上げ時に実行させるシェルスクリプトをCOPYする

下記の2つのシェルスクリプトをコピーするのだが、スクリプトの内容は後述

  1. httpd(Apache)をフォアグラウンドで起動するシェルスクリプト
  2. svnserve(svnのプロトコルでリポジトリにアクセス)のプロセスを起動する為のシェルスクリプト
Dockerfile
# 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する
このファイルは永続ボリュームにマウントし、後から編集できるようにしておくこと

Dockerfile
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/配下にコピーする。

Dockerfile
# 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点

  1. (ポートをデフォルトの80番からずらす場合)デフォルトでListenしているポートを書き換える
    (※)この場合、DockerfileEXPOSEで公開するポートも8080にする必要があるため注意すること
  2. 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内で直接行を編集する方が保守性が高い。

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が次のようになればよい

httpd.conf
# (中略)
#Listen 12.34.56.78:80
#Listen 80
Listen 8080
...
# (中略)
...
</IfModule>

Include conf/extra/svn.conf

1-8.コンテナの実行ユーザーの作成及び権限付与

rootユーザーでコンテナを起動するのはセキュリティ的にあまりよろしくないのでこのコンテナを実行する用のユーザーを作成しておく
何かあった時のために、このユーザーにsudo権限などを付加してしまっているが、不要な場合は削除してほしい

Dockerfile
# 実行ユーザーを作成するため、この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つである。

  1. 3690
    svn://のプロトコルで通信を行うポート
  2. 8080
    http://のプロトコルで通信を行うポート
  3. 443
    https://のプロトコルで通信を行うポート
Dockerfile
# 実行ユーザーの切り替え
USER $USERNAME

# http, https, svnのプロトコルでアクセスするためのポートをExpose
EXPOSE 3690 8080 443

1-10.Dockerfileの完成形

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を行う

apache/run.sh
#!/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を行う

subversion/run.sh
#!/bin/bash

exec /usr/bin/svnserve -d --foreground -r /home/svn/repos --listen-port 3690;

4.svn.conf

このファイルの中で次の設定を行う

  • Subversionの設定(リポジトリのパスなど)
  • LDAPの設定
svn.conf
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権限を持つのか定義したテキストファイルである

subversion-access-control
[groups]

[/]
* = rw

この場合、ルートディレクトリ([/])配下に対して、すべてのユーザー(*)が参照・編集権限を持つ(rw)ようになる
この辺りの設定に関しては次の記事に詳しくまとめられているので参考にしてほしい

7.docker-compose.yaml

言うまでもないが、Subversionコンテナの実行ユーザーはUID=999, GID=999で作成しているため、
ホストOSにマウントするディレクトリの所有者もchown -R 999:999 ...としておくのが望ましい
コンテナ名やマウントするディレクトリパスは各自の環境に合わせて適宜変更してほしい

docker-compose.yaml
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.コンテナイメージのビルド、立ち上げ

cmd
$ docker build -t subversion:latest .
...
$ docker-compose up -d
...

この段階で、http://localhost:8080にアクセスして次のようにApacheの画面が出れば起動成功である。
apache.jpg

8-2.レポジトリの作成

cmd
# 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にアクセスして次のようにレポジトリが作成されていることを確認してほしい。
testrepo.jpg

あとはTortoiseSVNを使ってアクセスするなりLDAPの設定を変更するなり自由に運用してほしい。

9.Git Repository

一応、ここまでのファイルはGitHubにアップしているので参考になれば幸いである。
GitHub : Subversion-Docker

お疲れ様でした。

参考サイト

7
8
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
7
8