VirtualBoxとDockerでお勉強用の環境を作ってみた
- 気になるソフトウェアを動かして、挙動を見てみたい。
- ソフトウェアの設定を変えていろいろ実験したい
- 複数のサーバーをつかうつもりでやってみたい
- 失敗時に自力で環境を戻す自信がない(戻すのがめんどくさい)ので、環境の再作成を頻繁にしたい
など思ったときに使っている、お試し環境の構築手順です。主に自宅などでのお勉強での使用を想定しています。
仮想マシンをVirtualBoxで作成し、そこにDockerをインストールします。
Dockerを使うと、プロセスを隔離環境(コンテナ)で実行できます。仮想マシンと違い、コンテナは気軽に作成/削除できるため、失敗を気にせずに気軽にいろいろ実験するにはもってこいです。
環境
種別 | OS | 備考 |
---|---|---|
ホスト(物理マシン) | Windows 10 Home 1909 | インターネットへ接続可能 |
ゲスト(仮想マシン) | CentOS Linux release 7.8.2003 | - |
目次
-
- 仮想マシンの構築
- 1.1 VirtualBoxのインストール
- 1.2 CentOS7イメージのダウンロード
- 1.3 仮想マシンの作成
- 1.4 ネットワーク接続設定
- 1.5 CentOS7インストール
- 1.6 インターネット接続の確認
-
- CentOS 7初期設定
- 2.1 カーネル最新化
- 2.2 パッケージの更新など
- 2.3 ホスト-ゲスト共有フォルダの有効化
- 2.4 一般ユーザーの作成
- 2.5 SSH設定
- 2.6 mDNS設定
-
- Visual Studio Codeの導入
-
- 開発環境の構築
- 4.1 Gitの最新化
- 4.2 Dockerのインストール
- 4.3 Python3のインストール
- 4.4 docker-composeのインストール
- 4.5 Visual Studio Code拡張機能インストール
-
- デモ
- 5.1 最低限のWebサイトを構築してみる
- 5.2 Apache Web Server + Tomcatで最小Webアプリを作ってみる
-
- まとめ
1. 仮想マシンの構築
1.1 VirtualBoxのインストール
VirtualBoxは仮想化ソフトウェアです。Windows用のインストーラーをダウンロードしてインストールします。インストール先はどこでもよいですが、ここではC:\App\VirtualBox
にインストールします。
1.2 CentOS7イメージのダウンロード
CentOS 7のDVDイメージを以下のURLからダウンロードします。時間がかかるので、気長に待ちます。
※ CentOS 8が既にリリースされていますが、まだDockerが公式にサポートしていません。
1.3 仮想マシンの作成
VirtualBoxマネージャーを開きます。新規
をクリックします。
仮想マシンの名前と保存先を指定します。今回は以下のように設定します。
メモリは2.0GBとします。必要に応じて変えてください。
仮想ハードディスクを固定サイズ32GBで作成します。Dockerイメージ分の容量を確保するため、このくらいにしておきます。
以上で仮想マシンの作成が終わりました。
1.4 ネットワーク接続設定
仮想マシンがホストのネットワークにブリッジ接続するようにします。ホストからインターネット接続できるのであれば、仮想マシンからもインターネット接続できるようになると思います。
1.5 CentOS 7インストール
先ほどダウンロードしたCentOS 7のイメージを仮想マシンの光学ドライブにセットします。
仮想マシンを起動してCentOS 7をインストールします。ネットワークの接続はインストール時にオンにしておきます。
1.6 インターネット接続の確認
rootユーザーで仮想マシンにログイン後、適当なインターネット上のWebサイトにアクセスできることを確認します。
# curl --head https://www.google.com/
HTTP/1.1 200 OK
Date: Sat, 14 Mar 2020 16:32:34 GMT
...
2. CentOS 7初期設定
不安であれば、作業前に仮想マシンのスナップショットを取っておくとよいです。
2.1 カーネル最新化
なんとなくカーネルを最新化してみます。以下を参考に実施していきます。
今回のカーネルのバージョンは以下です。
- デフォルト:3.10.0
- 最新:5.7.6
まずはELRepoを有効化します。
# yum install https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm
kernel-mlをインストールします。
# yum --enablerepo=elrepo-kernel install kernel-ml
# yum list installed kernel*
読み込んだプラグイン:fastestmirror
Loading mirror speeds from cached hostfile
* base: ftp.riken.jp
* elrepo: ftp.yz.yamagata-u.ac.jp
* extras: ftp.riken.jp
* updates: ftp.riken.jp
インストール済みパッケージ
kernel.x86_64 3.10.0-1127.el7 @anaconda
kernel-ml.x86_64 5.7.6-1.el7.elrepo @elrepo-kernel
kernel-tools.x86_64 3.10.0-1127.el7 @anaconda
kernel-tools-libs.x86_64 3.10.0-1127.el7 @anaconda
再起動後、新しいカーネル(5.7.6)で起動します。再起動後に以下のコマンドでカーネルのバージョンが最新版になっていることを確認します。
# uname --kernel-release
5.7.6-1.el7.elrepo.x86_64
残りの最新版カーネルパッケージをインストールします。yum swap
を使って、古いカーネルパッケージの削除と新しいカーネルパッケージのインストールを同時に行います。
# yum --enablerepo=elrepo-kernel \
swap \
-- install kernel-ml-* \
-- remove kernel kernel-tools kernel-tools-libs
※ yum swap
を使わずにそのままインストールしようとすると、古いものと依存関係が競合して失敗します。
エラー: kernel-ml-tools conflicts with kernel-tools-3.10.0-1127.13.1.el7.x86_64
エラー: kernel-ml-tools-libs conflicts with kernel-tools-libs-3.10.0-1127.13.1.el7.x86_64
これで新しいカーネルのインストールが完了しました。以下で確認します。
# yum list installed kernel*
読み込んだプラグイン:fastestmirror
Loading mirror speeds from cached hostfile
* base: ftp.riken.jp
* elrepo: ftp.yz.yamagata-u.ac.jp
* extras: ftp.riken.jp
* updates: ftp.riken.jp
インストール済みパッケージ
kernel-ml.x86_64 5.7.6-1.el7.elrepo @elrepo-kernel
kernel-ml-devel.x86_64 5.7.6-1.el7.elrepo @elrepo-kernel
kernel-ml-doc.noarch 5.7.6-1.el7.elrepo @elrepo-kernel
kernel-ml-headers.x86_64 5.7.6-1.el7.elrepo @elrepo-kernel
kernel-ml-tools.x86_64 5.7.6-1.el7.elrepo @elrepo-kernel
kernel-ml-tools-libs.x86_64 5.7.6-1.el7.elrepo @elrepo-kernel
kernel-ml-tools-libs-devel.x86_64 5.7.6-1.el7.elrepo @elrepo-kernel
2.2 パッケージの更新など
以下を実行して、CentOS 7のパッケージを最新化します。
# yum update
後で使うのでnet-toolsをインストールします。netstatコマンドが使えるようになります。
# yum install net-tools
終わったら、一度ゲストを再起動しておきます。
2.3 ホスト-ゲスト共有フォルダの有効化
ホスト-ゲストの間でフォルダの共有を行うことで、ファイルのやり取りを簡単にします。以下の情報を参考に実施します。
ゲストにVirtualBox - Guest Additionsのインストールが必要です。
まずは必要なパッケージをインストールします。
# yum groupinstall "development tools"
次に、Guest Additionsのディスクイメージを挿入します。ディスクイメージはWindowsホストであれば、VirtualBoxのインストールディレクトリにあります。
以下のようにマウントします。
# mkdir /media/cdrom
# mount /dev/cdrom /media/cdrom
mount: /dev/sr0 is write-protected, mounting read-only
# ls -l /media/cdrom
合計 45705
-r--r--r--. 1 root root 763 2月 20 22:27 AUTORUN.INF
dr-xr-xr-x. 2 root root 1824 5月 15 03:49 NT3x
dr-xr-xr-x. 2 root root 2652 5月 15 03:49 OS2
-r--r--r--. 1 root root 547 5月 15 03:49 TRANS.TBL
-r--r--r--. 1 root root 3755310 5月 15 03:41 VBoxDarwinAdditions.pkg
-r-xr-xr-x. 1 root root 3949 5月 15 03:41 VBoxDarwinAdditionsUninstall.tool
-r-xr-xr-x. 1 root root 6737330 5月 15 03:42 VBoxLinuxAdditions.run
-r--r--r--. 1 root root 9317888 5月 15 04:43 VBoxSolarisAdditions.pkg
-r-xr-xr-x. 1 root root 16832808 5月 15 03:46 VBoxWindowsAdditions-amd64.exe-r-xr-x
r-x. 1 root root 9863040 5月 15 03:45 VBoxWindowsAdditions-x86.exe
-r-xr-xr-x. 1 root root 270616 5月 15 03:43 VBoxWindowsAdditions.exe
-r-xr-xr-x. 1 root root 6384 5月 15 03:42 autorun.sh
dr-xr-xr-x. 2 root root 792 5月 15 03:49 cert
-r-xr-xr-x. 1 root root 4821 5月 15 03:42 runasroot.sh
Guest Additionsをインストールします。以下のコマンドを実行します。
# cd /media/cdrom
# sh ./VBoxLinuxAdditions.run
共有フォルダを設定するために、一度仮想マシンをシャットダウンします。終わったら仮想マシンの設定画面から共有フォルダの設定を開き、以下のように設定します。パスはお好みで設定してください。
- ホスト(Windows)のフォルダ:
C:\shared\centos7_sandbox
- ゲスト(CentOS 7)のマウント先ディレクトリ:
/mnt/host
これで指定したフォルダをホスト-ゲスト間で共有することができるようになりました。
2.4 一般ユーザーの設定
常にrootユーザーで作業するのは好ましくないです。root権限が不要の場面では一般ユーザーを使います。
ユーザーを作成します。名前はすきにつけましょう。ここではrolengraysとします。パスワードも設定しましょう。
# useradd --user-group rolengrays
# passwd rolengrays
2.3節で設定した共有フォルダにアクセスするためには、vboxsf
グループに入る必要があります。
# usermod -aG vboxsf rolengrays
rolengraysユーザーでsudoできるようにします。sudoersファイルの文法エラーを防ぐため、visudoコマンドから編集します。
# visudo -f /etc/sudoers.d/rolengrays
ファイルの内容は以下の一行のみとします。
rolengrays ALL = (ALL) ALL
2.5 SSH接続設定
2.4節で作成したユーザーでホストからSSH接続できるようにします。3節で使います。
ホストで、SSH用鍵を作成します。最近のWindows10にはデフォルトでSSHクライアント(OpenSSH)がインストールされています。
(ホストで実行)
C:\> ssh-keygen -t rsa -b 2048 -N "" -f %USERPROFILE%\.ssh\rolengrays.key
ホストで、公開鍵のほうを共有フォルダにコピーします。
(ホストで実行)
c:\> copy %USERPROFILE%\.ssh\rolengrays.key.pub C:\shared\centos7_sandbox
1 個のファイルをコピーしました。
ゲストで、公開鍵認証の有効化するため、/etc/ssh/sshd_config
を編集してPubkeyAuthentication yes
のコメントアウトを外します。
(ゲストで実行)
...
- # PubkeyAuthentication yes
+ PubkeyAuthentication yes
...
終わったらsshdを再起動して設定を反映します。
(ゲストで実行)
# systemctl restart sshd
以下のようにrolengraysユーザーの公開鍵を登録します。パーミッションは正しく設定しないとSSH接続が失敗します。
(ゲストで実行)
# su - rolengrays
$ mkdir --mode 700 ${HOME}/.ssh
$ cat /mnt/host/rolengrays.key.pub >> ${HOME}/.ssh/authorized_keys
$ chmod 600 ${HOME}/.ssh/authorized_keys
後で使うので、ゲストのIPアドレスを調べておきます。
(ゲストで実行)
$ ip address
ホストの%USERPROFILE%\.ssh\config
にSSH設定ファイルを作成します。調べたIPアドレスをHostNameに指定します。
Host centos7_sandbox
HostName 192.168.43.119
User rolengrays
IdentityFile "~/.ssh/rolengrays.key"
ホストからSSH接続してみます。SSH経由でコマンドを正しく実行できることを確認します。
(ホストで実行)
c:\>ssh centos7_sandbox cat /etc/redhat-release
CentOS Linux release 7.8.2003 (Core)
2.6 mDNS設定
2.5節の手順で仕組み上はSSH接続ができるようになりました。しかし、DHCPで各ホストにIPアドレスを動的に割りあてている場合、ゲストのIPアドレスが意図せず変更されることがあります。そうなるとまたゲストのIPアドレスを調べおして、%USERPROFILE%\.ssh\config
を更新する必要があります。これでは面倒なので、mDNSの仕組みを使って同じネットワーク内のIPアドレスをホスト名で解決できるようにします。
※ Windows 10のバージョンが古いと、mDNSクライアントがデフォルトで入っていない場合があります。
まずはゲストにホスト名を設定します。自分の好きな名前を付けましょう。ここではc7sandbox
とします。終わったら、ゲストを再起動しておきます。
(ゲストで実行)
# hostnamectl set-hostname c7sandbox
続いて、ゲストにmDNSデーモンをインストールします。
(ゲストで実行)
# yum install avahi
avahi-daemonサービスを起動します。自動起動もONにしておきます。
(ゲストで実行)
# systemctl enable avahi-daemon
# systemctl start avahi-daemon
5353/UDPがLISTENしていることを確認します。
(ゲストで実行)
# netstat -nulp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
udp 0 0 0.0.0.0:40913 0.0.0.0:* 1464/avahi-daemon:
udp 0 0 0.0.0.0:68 0.0.0.0:* 865/dhclient
udp 0 0 0.0.0.0:5353 0.0.0.0:* 1464/avahi-daemon:
udp 0 0 127.0.0.1:323 0.0.0.0:* 718/chronyd
udp6 0 0 ::1:323 :::* 718/chronyd
最後にfirewalldの設定を変更し、外から5353/UDPへの通信を許可するようにします。デフォルトゾーンをhomeにします。
(ゲストで実行)
# firewall-cmd --set-default-zone=home
success
homeゾーンが、現在使っているインターフェースに設定されていることを確認します。
(ゲストで実行)
# firewall-cmd --get-active-zones
home
interfaces: enp0s3
※ homeゾーンではmdnsサービスがデフォルトで有効に設定されています。以下のコマンドで確認します。
(ゲストで実行)
# firewall-cmd --zone home --list-services
dhcpv6-client mdns samba-client ssh
※ mdnsサービスは5353/UDPを許可しています。
(ゲストで実行)
# firewall-cmd --service mdns --get-ports --permanent
5353/udp
firewalldを再起動して設定を反映します。
(ゲストで実行)
# systemctl restart firewalld
ホストの、%USERPROFILE%\.ssh\config
ファイルを書き換えます。ゲストのホスト名がc7sandbox
なので、末尾に.local
をつけたものをHostNameに指定します。
※ mDNSはデフォルトで、"ホスト名 + .local"で名前解決するためです。
Host centos7_sandbox
HostName c7sandbox.local
User rolengrays
IdentityFile "~/.ssh/rolengrays.key"
ホストからもう一度SSHできることを確認します。
(ホストで実行)
c:\>ssh centos7_sandbox hostname
c7sandbox
これでIPアドレスではなく、名前でホストからゲストにSSH接続ができました。
3. Visual Studio Codeの導入
Visual Studio Codeをインストールします。このテキストエディタには豊富な拡張機能があり、開発を強力にサポートしてくれます。
Remote Development拡張機能をインストールします。これを使うと、ゲストのファイルをホストで簡単に編集できます。
2.4節、2.5節のSSH設定ファイルをこの拡張機能が認識しているので、すぐにSSH接続できます。
4. 開発環境の構築
不安な場合は仮想マシンのスナップショットを取っておくとよいです。
4.1 Gitの最新化
開発環境ではバージョン管理システムが必要となる場面が多いです。Gitを使うことにします。ここまでの作業を実施している場合、既にGitがインストールされていますが、バージョンが古いので最新化します。(4.5節で導入するVisual Studio CodeのGit拡張機能がGitのバージョン2.0以上でうまく動作するため。)
現在のGitのバージョン(CentoOS 7デフォルト)は以下です。
# git --version
git version 1.8.3.1
執筆時点の最新版は2.27.0
です。手順は以下を参考にします。
ビルド前の準備します。Gitのビルドに必要な以下のパッケージをインストールします。
# yum install \
zlib-devel \
perl-devel \
openssl-devel \
curl-devel \
expat-devel \
gettext-devel
ドキュメントのビルドに必要な以下のパッケージをインストールします。(ドキュメントはいらないかもしれませんが...)
# yum install \
asciidoc \
xmlto
既にある古いGitでGitそのもののリポジトリをcloneしてきます。
# cd /tmp
# git clone https://github.com/git/git.git
最新版をチェックアウトします。
# cd /tmp/git
# git checkout v2.27.0
ビルド/インストールします。インストール先は/usr/local
にします。少し時間がかかるので気長に待ちましょう。
# make configure
# ./configure --prefix=/usr/local
# make all doc
# make install install-doc install-html
hashをリセットしたあと、新しいGitのバージョンを確認します。
# hash -r
# git --version
git version 2.27.0
4.2 Dockerのインストール
Docker Engineをインストールします。Dockerによって、プロセスを隔離した環境で実行できます。以下を参考にします。
必要なパッケージをインストールします。
# yum install \
yum-utils \
device-mapper-persistent-data \
lvm2
リポジトリを有効化します。
# yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
インストールします。
# yum install \
docker-ce \
docker-ce-cli \
containerd.io
dockerサービスの自動起動を有効化、起動します。
# systemctl enable docker
# systemctl start docker
動作確認します。
# docker run hello-world
4.2.1 dockerグループへの追加
rolengraysユーザーをdockerグループに追加します。これでsudoなしでrolengraysユーザーがdockerコマンドを実行できます。
# usermod -aG docker rolengrays
※ ユーザーdockerグループに追加すると、Dockerホストでそのユーザーにroot権限を与えることとほぼ同じとなります。
4.3 Python3のインストール
Python3をインストールします。あとでインストールするdocker-composeの1.25.x
以降のバージョンがPython2をサポートしないためです。(そしてPython2は既に公式のサポートが切れています。)CentOS 7はデフォルトだとPython2しかインストールされていません。
以下を参考にインストールします。
必要なパッケージをインストールします。
# yum groupinstall "development tools"
# yum install \
bzip2-devel \
gdbm-devel \
libffi-devel \
libuuid-devel \
ncurses-devel \
openssl-devel \
readline-devel \
sqlite-devel \
tk-devel \
wget \
xz-devel \
zlib-devel
ソースコードをダウンロードします。
# cd /tmp
# wget https://www.python.org/ftp/python/3.8.3/Python-3.8.3.tgz
# tar -xzf Python-3.8.3.tgz
ビルド・インストールします。
# cd /tmp/Python-3.8.3
# ./configure --enable-shared
# make
# make install
# sh -c "echo '/usr/local/lib' > /etc/ld.so.conf.d/custom_python3.conf"
# ldconfig
バージョンを確認します。
# python3 --version
Python 3.8.3
4.4 docker-composeのインストール
docker-composeは同時に複数のコンテナを使うアプリケーションを定義・実行できるツールです。コンテナの実行はdockerコマンドでも実施できますが、オプションが長いコマンドを複数回打つのは非常に面倒です。docker-composeはこの問題を解決できます。以下の通りインストールします。
執筆時点の最新版は1.26.0
です。
# curl -L "https://github.com/docker/compose/releases/download/1.26.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# chmod +x /usr/local/bin/docker-compose
# docker-compose --version
docker-compose version 1.26.0, build d4451659
4.5 Visual Studio Code拡張機能のインストール
以下の拡張機能をインストールしておきます。細かい機能は紹介しませんが、便利です。実際にインストールして機能を確かめてみてください。
- GitLens(行ごとのBlameができる、ファイルの編集履歴をGUIで確認できる、など)
- Docker(実行中のコンテナや手元にあるイメージなどをGUIで表示してくれる、など)
ここまでで、環境構築は終わました。
5. デモ
利用例を紹介します。
5.1 最低限のWebサイトを構築してみる
最低限のWebサイトをDockerコンテナで構築してみます。最終的にカレントディレクトリ配下は以下のようになります。
.
├── c7-base
│ └── Dockerfile
├── c7-systemd
│ └── Dockerfile
└── docker-compose.yml
5.1.1 systemd有効コンテナイメージの作成
systemdを有効にしたコンテナの定義を作成します。./c7-systemd/Dockerfile
を以下のようにします。centos - Docker HubからDockerfileを引用します。
# https://hub.docker.com/_/centos より引用
FROM centos:7
ENV container docker
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == \
systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
CMD ["/usr/sbin/init"]
c7-systemdのコンテナイメージをビルドします。
$ docker build -t local/c7-systemd ./c7-systemd
5.1.2 自分の基本イメージの作成
基本イメージを作成します。目的にかかわらず、自分がよく使う汎用パッケージや設定などをあらかじめコンテナイメージにしておくと便利です。./c7-base/Dockerfile
を以下のようにします。先ほどビルドしたlocal/c7-systemd
をベースにした上で、よく使うパッケージを自分で適当に選んでインストールするとよいです。デフォルトだとタイムゾーンがUTCなので、JSTに設定しておきます。
FROM local/c7-systemd
# アップデート&パッケージインストール
RUN yum update -y \
&& yum install -y \
wget \
tree \
which \
net-tools
# タイムゾーン設定
RUN /usr/bin/ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
こちらもビルドします。
$ docker build -t local/c7-base ./c7-base
5.1.3 docker-compose.ymlの作成
docker-compose.ymlを作成します。通常、Dockerコンテナを実行するためには、場合によっては長いコマンドラインオプションを複数打たなければならず、面倒です。./docker-compose.yml
を以下のようにします。コンテナ1つだけ定義します。
---
version: "3.7"
services:
c7-base:
build:
context: ./c7-base
image: local/c7-base
container_name: c7-base
working_dir: /root
privileged: true # systemdをコンテナ内で使用するための設定
stdin_open: true
tty: true
# Dockerホストの'8080/TCP'をコンテナの'80/TCP'にマッピングするため
ports:
- published: 8080
target: 80
protocol: tcp
mode: host
volumes:
# systemdをコンテナ内で使用するための設定
- type: bind
source: /sys/fs/cgroup
target: /sys/fs/cgroup
read_only: true
※ 上記のdocker-compose定義でのコンテナ実行は、以下のコマンドとほぼ同等です。
# docker run -it --privileged -w /root -p 8080:80 -v /sys/fs/cgroup:/sys/fs/cgroup:ro --name c7-base local/c7-base
5.1.4 コンテナ内でのWebサーバーの作成作業
docker-composeでdockerコンテナを起動します。
$ docker-compose -f ./docker-compose.yml up -d
dockerコンテナにシェルをアタッチします。Visual Studio CodeのDocker拡張機能を使えば、コマンドなしでできます(コンテナを右クリック->Attach Shell)。
[rolengrays@c7sandbox ~]$ docker exec -it c7-base /bin/bash
[root@0b7b64ad6eb6 ~]#
これでコンテナ内でコマンドを実行できるようになりました。試しにhttpdをインストールして、コンテナ内にWebサーバーを作ってみます。内容が"Hello From Container"のみの簡単なHTMLドキュメントも用意しておきます。
(コンテナ内で実行)
# yum install httpd
# echo "Hello From Container" > /var/www/html/index.html
# systemctl start httpd
終わったらexit
コマンドで抜けます。
5.1.5 コンテナ内のWebサーバーにアクセス
ホストからこのWebサーバーにアクセスしてみます。ゲストの'8080/TCP'をコンテナの'80/TCP'にマッピングするように設定しているため、firewalldに8080/TCPを許可する設定をする必要があります。
まずはサービスを作成します。名前はhttp_8080
とします。以下のようなXMLファイルを作成すればOKです。
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>HTTP(8080)</short>
<description>HTTP 8080 Port</description>
<port protocol="tcp" port="8080"/>
</service>
ファイルを作成したら、リロードします。
(ゲストで実行)
# firewall-cmd --reload
次にhomeゾーンに先ほど作成したhttp_8080
を追加します。追加したら、もう一度リロードします。
(ゲストで実行)
# firewall-cmd --permanent --zone home --add-service http_8080
# firewall-cmd --reload
これで8080/TCPに外からアクセスできるようになりました。ホストでWebブラウザを立ち上げて、http://c7sandbox.local:8080/index.html
にアクセスしてみましょう。Hello From Container
が表示されれば成功です。
Webサーバーのインストールを最初からやり直したい場合は、以下のように一度downしてから、再度upすることで環境(コンテナ)を再構築できます。
$ docker-compose down
$ docker-compose up -d
これでインストールからやり直すことができます。今回はhttpdをインストールするだけの例ですが、代わりにnginxをインストールしてみたりと、ほかにもいろいろな実験を行うことができます。もう一度シェルをアタッチしてアクセスログを見たりもできます。
5.2 Apache Web Server + Tomcatでデモ用Webアプリを作ってみる
複数のコンテナを使用するパターンで試してみます。Apache Web ServerのコンテナとTomcatのコンテナを作成し、それらを連携させてみます。プロジェクトのディレクトリ構成は最終的に以下のようになります。
demo52
├── app
│ ├── Dockerfile
│ ├── build.sh
│ ├── conf
│ │ └── server.xml
│ ├── resource
│ │ ├── apache-tomcat-9.0.36.tar.gz
│ │ └── openjdk-14.0.1_linux-x64_bin.tar.gz
│ └── testapp
│ ├── pom.xml
│ (略)
├── docker-compose.yml
└── proxy
├── Dockerfile
└── conf
└── app.conf
以下に簡単なイメージを載せておきます。
5.2.1 テスト用Webアプリの作成
Tomcatの上で動かす簡単なアプリを作ります。ビルドツールはMavenを使います。公式のDockerイメージを使いましょう。
まずはDockerホスト側にMavenローカルリポジトリを作成します。これをコンテナ内に置いてしまうと、コマンド実行後にダウンロードしたパッケージがコンテナごと破棄されてしまいます。こうなると2度目のビルド以降も大量のダウンロードが発生するため、時間の無駄になります。コンテナ実行後も永続化したいファイルはコンテナ外(ここではDockerホスト)に配備するのがよいです。
$ mkdir -p ${HOME}/data/maven_repo
以下のようにディレクトリを作成しておきます。
# mkdir -p ./app/conf ./app/resource ./proxy/conf
次にMavenでWebアプリプロジェクトのひな形を作ります。公式からMavenイメージをpullしてから、コンテナを作成・実行して必要なパッケージのダウンロードなどを行うため、少し時間がかかります。
$ docker run \
-it \
--rm \
--name my-maven-project \
-v $(pwd)/app:/usr/src/mymaven \
-v ${HOME}/data/maven_repo:/root/.m2 \
-w /usr/src/mymaven \
maven:3.6.3-jdk-14 mvn archetype:generate \
-DinteractiveMode=false \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-webapp \
-DarchetypeVersion=1.4 \
-DgroupId=com.rolengrays.example \
-DartifactId=testapp \
-Dversion=1.0.0
終わったら、./app/testapp
というディレクトリができているはずです。
./app/testapp
├── pom.xml
└── src
└── main
└── webapp
├── WEB-INF
│ └── web.xml
└── index.jsp
特にユーザーを指定せずにDockerコンテナからファイルを作成したので、所有者がrootユーザーになっています。自分のユーザーにしましょう。
$ sudo chown -R rolengrays:rolengrays ./app/testapp
次にpom.xml
を編集します。今回はJDK14を使いたいので、デフォルトから以下のように書き換えます。
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <maven.compiler.source>1.7</maven.compiler.source>
- <maven.compiler.target>1.7</maven.compiler.target>
+ <maven.compiler.source>1.14</maven.compiler.source>
+ <maven.compiler.target>1.14</maven.compiler.target>
</properties>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
+ <configuration>
+ <source>14</source>
+ <target>14</target>
+ </configuration>
</plugin>
各種ソースファイルを準備します。
$ mkdir -p ./app/testapp/src/main/java/com/rolengrays/example
Hello.java
では、単純な文字列を生成するだけのクラスを定義します。
package com.rolengrays.example;
public class Hello {
public Hello() {}
public static String greetings() { return new String("Hello From Container Web App"); }
}
index.jsp
では、Helloクラスに文字列を出力させます。
<%@ page import="com.rolengrays.example.Hello" %>
<html>
<body>
<h2>
<% out.println(Hello.greetings()); %>
</h2>
</body>
</html>
ソースの準備が終わったので、ビルドしましょう。コマンドが長いため、ビルドスクリプトを作っておきます。
#!/bin/bash
docker run \
--rm \
--name my-maven-project \
-v "$(pwd)/app/testapp":/usr/src/mymaven \
-v ${HOME}/data/maven_repo:/root/.m2 \
-w /usr/src/mymaven \
maven:3.6.3-jdk-14 mvn package
$ chmod +x ./app/build.sh
$ ./app/build.sh
※ multi-stage buildで、コンテナイメージのビルド時にWebアプリのビルドを行い、成果物(warファイル)だけをコンテナイメージに残す方法があります。しかし、コンテナイメージのビルド時にMavenのローカルリポジトリを参照するうまい方法がないため、ビルドのたびに大量のダウンロードが発生します。それを避けるため、今回はWebアプリのビルドをコンテナイメージのビルド前にいちいち手動で行うこととします。
5.2.2 Tomcatのコンテナイメージの作成
必要なソフトウェアをダウンロードします。
ソフトウェア | ダウンロードページ | 保存先 |
---|---|---|
OpenJDK 14 | https://jdk.java.net/14/ | ./app/resource/openjdk-14.0.1_linux-x64_bin.tar.gz |
Tomcat 9 | https://tomcat.apache.org/download-90.cgi | ./app/resource/apache-tomcat-9.0.36.tar.gz |
$ ls -l ./app/resource
合計 204952
-rw-rw-r--. 1 rolengrays rolengrays 11200905 6月 4 03:03 apache-tomcat-9.0.36.tar.gz
-rw-rw-r--. 1 rolengrays rolengrays 198665889 3月 5 19:40 openjdk-14.0.1_linux-x64_bin.tar.gz
TomcatがApache Web ServerとAJP通信できるように設定をします。Tomcat 9のアーカイブからserver.xml
を抜き出して、./app/conf
に配備します。
$ tar -C /tmp -xzf ./app/resource/apache-tomcat-9.0.36.tar.gz apache-tomcat-9.0.36/conf/server.xml
$ cp /tmp/apache-tomcat-9.0.36/conf/server.xml ./app/conf
$ rm -rf /tmp/apache-tomcat-9.0.36
その後、./app/conf/server.xml
のAJP設定部分を以下のように編集します。(デフォルトだとコメントアウトされています。)
<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector protocol="AJP/1.3"
secretRequired="false"
address="0.0.0.0"
port="8009"
redirectPort="8443" />
-
secretRequired="false"
属性を追加します。ないとエラーになります。true
にした場合はほかにもいろいろ設定が必要で手間がかかるため、ここでは明示的にfalse
を設定します。 -
address
属性値を0.0.0.0
に書き換えます。デフォルトはaddress
が::1
でIPv6になっていますが、今回はDockerコンテナ・ネットワークをIPv6で構成していないため、IPv4でもListenできるように0.0.0.0
に書き換えます。
./app/Dockerfile
を作成します。
# 5.1節で作成した自分の基本イメージをベースとする
FROM local/c7-base
# 変数
ARG java_home="/usr/local/java/jdk-14.0.1"
ARG catalina_home="/usr/local/tomcat/apache-tomcat-9.0.36"
# JDK14のインストール
ADD ./resource/openjdk-14.0.1_linux-x64_bin.tar.gz /usr/local/java
ENV JAVA_HOME ${java_home}
# Tomcat9のインストール
ADD ./resource/apache-tomcat-9.0.36.tar.gz /usr/local/tomcat
ENV CATALINA_BASE ${catalina_home}
ENV CATALINA_HOME ${catalina_home}
## AJPの設定を記述したserver.xmlをコピー
COPY ./conf/server.xml ${catalina_home}/conf/server.xml
# ビルドしたwarの配備
COPY ./testapp/target/testapp.war ${catalina_home}/webapps
CMD [ "/bin/bash", "-c", "${CATALINA_HOME}/bin/catalina.sh run" ]
5.2.3 AJPプロキシのコンテナイメージの作成
Apache Web ServerをAJPプロキシサーバーとして構成します。以下のVirtualHost定義を作成します。これでプロキシサーバーへのアクセスをWebアプリサーバーの/testapp/
パスへ転送します。
<VirtualHost *:80>
ServerName c7sandbox.local
ProxyPass / ajp://app:8009/testapp/
</VirtualHost>
FROM local/c7-systemd
RUN yum install -y httpd && systemctl enable httpd
COPY ./conf/app.conf /etc/httpd/conf.d/app.conf
5.2.4 Webアプリの構築
docker-composeの定義を作成します。以下の通り、2種類のコンテナを定義します。
---
version: "3.7"
services:
# AJPプロキシサーバーのコンテナ
proxy:
build:
context: ./proxy
image: local/proxy
networks:
- testnet
privileged: true
stdin_open: true
tty: true
ports:
- target: 80
published: 8080
protocol: tcp
mode: host
volumes:
- type: bind
source: /sys/fs/cgroup
target: /sys/fs/cgroup
read_only: true
# Webアプリサーバーのコンテナ
app:
build:
context: ./app
image: local/app
container_name: app # プロキシサーバーからappで名前解決できるようになります。
networks:
- testnet
privileged: true
stdin_open: true
tty: true
volumes:
- type: bind
source: /sys/fs/cgroup
target: /sys/fs/cgroup
read_only: true
networks:
testnet:
5.2.5 コンテナの実行
コンテナを実行します。--build
でコンテナイメージをビルドしてから実行します。
$ docker-compose up -d --build
※ 5.1節で起動したコンテナが残っていたら、上記を実行する前に停止してください。
ホストOSでブラウザからhttp://c7sandbox.local:8080/
にアクセスしてみましょう。以下のようにHello From Container Web App
が表示されれば成功しています。
設定変更などでいろいろ実験したい場合は、Dockerコンテナ内にシェルをアタッチして環境を手動で変更できます。もちろん、コマンドの代わりにVisual Studio CodeのDocker拡張機能を使ってアタッチしてもよいです。
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
08d677a1ce69 local/proxy "/usr/sbin/init" 2 minutes ago Up 2 minutes 0.0.0.0:8080->80/tcp demo52_proxy_1
edc3f676c012 local/app "/bin/bash -c '${CAT…" 2 minutes ago Up 2 minutes app
プロキシサーバーのコンテナ名をdocker-compose.yml
で指定していないため、docker-composeが自動で命名しています。
$ docker exec -it demo52_proxy_1 /bin/bash
$ docker exec -it app /bin/bash
初期状態にコンテナを戻したい場合は、5.1節でやったように以下のコマンドを実行します。Dockerfileを編集した場合は、--build
オプションをつけてupしましょう。
$ docker-compose down
$ docker-compose up -d --build
6. まとめ
今回は、VirtualBoxとDockerで開発環境を構築してみました。Dockerで環境を隔離できて作り直しも楽なので、いろんなことを気軽に実験できます。