9
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

http:// or https://のプロトコルで通信を行うため、Subversionに加えてApache-Httpdが含まれるコンテナイメージを構築する。
※ 正確には、 Apache-HttpdのコンテナにSubversionをInstallする という表現が正しい。

Apache-Httpdのコンテナイメージは、httpdという名称でApacheから公式イメージが提供されているのでそれを使用する

Dockerfile
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のリポジトリ用のディレクトリを作成する

Dockerfile
# リポジトリ用のディレクトリを作成
RUN	mkdir -p /home/svn/repos &&\
    mkdir -p /run/apache2/ &&\
	mkdir -p /etc/subversion &&\
	touch /etc/subversion/passwd

尚、上記で作成したディレクトリパスはsvn.conf内に指定する必要がある。
svn.conf内に指定する具体的な手順は4. svnconfを参照していただきたい。

1-4.コンテナ内のユーザーを管理するテキストファイルをCOPYする

Subversionコンテナ内でのみ有効なローカルユーザーを管理するlocaluser.listというテキストファイルを用意し、コンテナ内にCOPYする処理を記述する。
このテキストファイルの内容はSVNの初期ユーザーのID("admin")、パスワード("admin" MD5形式で保存)だが、『5. localuserlist』の項目で細かく説明する。

Dockerfile
COPY localuser.list /home/svn/localuser.list

上記のファイルをCOPYする理由は、LDAP認証ができない場合に備え、ローカルユーザーでもアクセスできるようにするためである。
このlocaluser.listというテキストファイルはsvn.confから読み込むようにsvn.confに設定を追加する。詳しくは『4. svnconf』を参照。

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.ユーザーごとのアクセスコントロールを定義するファイルを作成

Dockerfileが存在するディレクトリにsubversion-access-controlというファイルを置いて、ビルド時にコンテナイメージの中にCOPYする。
このファイルはSubversionを利用するユーザーの権限を記載するためのテキストファイルである。詳しくは『6. subversion-access-control』を参照。

Dockerfile
COPY subversion-access-control /etc/subversion/subversion-access-control
RUN chmod a+w /etc/subversion/* && chmod a+w /home/svn

docker-compose.yamlを作成する際に気を付けてほしいのだが、このファイルは格納されているフォルダ(/etc/subversion/)ごと永続ボリュームにマウントし、後から編集できるようにしておくことをおススメする。

1-7.httpアクセスのためにコンテナ内のファイルを編集

1-7-1.必要なモジュールをコンテナ内のディレクトリから別のディレクトリへコピー

DockerHubからPullしたhttpdイメージには、既にhttp://またはhttps://のプロトコルでSubversionにアクセスする際 必要なモジュールが存在する。
しかしこのモジュールは/usr/lib/apache2/modules/配下に存在しており、そのままでは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/

1-7-2.httpdの設定ファイルを編集

httpd.conf(httpdの設定ファイル)も編集が必要である。編集内容は下記の2点

  1. (ポートをデフォルトの80番からずらす場合)デフォルトでListenしているポートを書き換える
    ※ この場合、DockerfileEXPOSEで公開するポートも8080にする必要があるため注意すること
  2. httpd.confからsvn.conf(Subversionの設定ファイル)を読み込むように編集する
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
# Subversionの設定ファイルをCOPYする
# COPY先の/usr/local/apache2/conf/extra/は、ちょうど上の処理(echo 'Include conf/extra/svn.conf' >> /usr/.../httpd.conf)でhttd.confに追記したPATHになる
COPY svn.conf /usr/local/apache2/conf/extra/

【補足: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内で直接行を編集する方が保守性が高い。
(ここまで補足)

結果として、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
# 立ち上げたコンテナ内で"admin"というユーザーIDの初期ユーザーを作成
subversion:$ htpasswd -c -m localuser.list admin
New password:
Re-type new password:
Adding password for user admin
# もし"admin2"という別のユーザーを追加する場合には -c のオプションを外す
# -c のオプションをつけたままだと既存のファイルを削除したうえで新しいファイルが作成されてしまうので注意
subversion:$ htpasswd -m localuser.list 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
# 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

お疲れ様でした。

参考サイト

9
11
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
9
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?