この記事はニフクラ 等を提供している、富士通クラウドテクノロジーズ Advent Calendar 2022 の15日目の記事です。
前日は @earth429さんのSpotifyのNowPlayingを投稿しステータスに設定もしてくれるSlackbotを作ってみたでした。
弊社にはSlackに現在聞いている曲を共有するチャンネルがあるのですが、そのチャンネルでめちゃくちゃ活躍してくれそうだなと感じました。
AppleMusic版もほしいな、、
はじめに
本記事では、ブラウザから「コンテナ作成」ボタンを押すだけでサーバ上にDockerコンテナを作成する方法について記述します。
最低限の構成を紹介するので、必要に応じて増やしたり減らしたりしてみてください。
やってることは簡単なことの組み合わせだと思います。(方法2は少し難しいかも)
方法1と方法2を記述するので、好きな方を選んでください。
おすすめは方法2です。
ゴール
- ブラウザ(chromeやfirefoxなど)から「コンテナ作成」のボタンを押すと、裏で動いているサーバ上にDockerコンテナが作成されること
- ブラウザから作成したコンテナにアクセスできること(今回はApacheコンテナ)
方法1,2の違い
方法1
- APIサーバからAPPサーバのDockerを操作する(
docker -H
) -
docker -H
が公式から推奨されていない - 実装内容の理解は簡単かも
- UIサーバ、APIサーバ、APPサーバで合計3台のサーバが必要
方法2
- APPサーバ上でAPPサーバのDockerを操作する
- DockerAPIを直接叩くので実装内容理解がちょっと大変かも
- Docker公式非推奨の方法を避けることができる
- (この記事ではAPIサーバを用意したが)APIサーバを省いてUIサーバとAPPサーバの2台で構成できる
構成図
環境
- UIサーバ
- CentOS7.4.1708
- Apache/2.4.6
- PHP7.4.30
- APIサーバ
- CentOS7.4.1708
- Apache/2.4.6
- Docker20.10.17
- PHP7.4.30
- APPサーバ
- CentOS7.4.1708
- Apache/2.4.6
- Docker20.10.17
実装の流れ
方法1,2共通
- UIサーバ,APIサーバ,APPサーバを作成する
- UIサーバにApache、PHPをインストール
- APIサーバにApache、Docker、PHPをインストール
- APPサーバにApache、Dockerをインストール
- FWの設定
方法1
6. APIサーバからAPPサーバのDockerを操作できるように設定
7. UIサーバ上にHTML,PHPのファイルを配置
8. APIサーバ上にPHPのファイルを配置
9. APPサーバ上に使いたいコンテナイメージを入れる
10. 動作確認
方法2
6. APPサーバのDockerをDockerAPIで直接叩けるように設定
7. UIサーバ上にHTML,PHPのファイルを配置
8. APIサーバ上にPHPのファイルを配置
9. APPサーバ上にPHPのファイルを配置
10. APPサーバ上に使いたいコンテナイメージを入れる
11. 動作確認
以下、実装の流れに沿って解説していきます。
方法1,2共通
UIサーバ,APIサーバ,APPサーバを作成する
好きなサービス、もしくは自前でUIサーバ,APIサーバ,APPサーバを作成してください。
今回はCentOS7.4の想定で進めます。
UIサーバにApache、PHPをインストール
UIサーバにApache、PHPをインストールします。
yum -y install httpd
yum -y install http://rpms.remirepo.net/enterprise/remi-release-7.rpm
yum -y install --enablerepo=remi,remi-php74 php php-mbstring php-xml
APIサーバにApache、Docker、PHPをインストール
APIサーバにApache、Docker(方法1のみ)、PHPをインストールします。
yum -y install httpd
## 方法1のみ
yum -y install yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum -y install docker-ce
yum -y install http://rpms.remirepo.net/enterprise/remi-release-7.rpm
yum -y install --enablerepo=remi,remi-php74 php php-mbstring php-xml
参考
Docker CEをCentOS 7にyumインストールする手順
CentOS7へPHP7.4をインストール
APPサーバにApache、Docker、PHPをインストール
APPサーバにApache(方法2のみ)、Docker、PHP(方法2のみ)をインストールします。
## 方法2のみ
yum -y install httpd
yum -y install yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum -y install docker-ce
## 方法2のみ
yum -y install http://rpms.remirepo.net/enterprise/remi-release-7.rpm
yum -y install --enablerepo=remi,remi-php74 php php-mbstring php-xml
参考
Docker CEをCentOS 7にyumインストールする手順
FWの設定
それぞれのサーバ間で通信できるように&UIサーバのコンテンツをブラウザから見られるようにFWのINルールを追加します。
UIサーバはコンテナ作成ボタンを配置するためのサーバなので、/var/www/html/
配下がブラウザから見れる必要があります。
- ブラウザ→UIサーバ...80番ポート(http用)
- ブラウザ→APPサーバ...8080番ポート(作成したコンテナアクセス用)
- UIサーバ→APIサーバ...80番ポート(http用)
- APIサーバ→APPサーバ...2375番ポート(Docker用)※方法1の場合のみ
- APIサーバ→APPサーバ...80番ポート(http用)※方法2の場合のみ
方法1
APIサーバからAPPサーバのDockerを操作できるように設定
APIサーバからAPPサーバのDockerを操作できるようにdocker -H
のオプションを使えるようにします。
警告
この方法はDocker公式サイトで非推奨とされています。使用する場合は注意してください。
APPサーバに/etc/docker/daemon.json
を作成、追記します。
{"hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2375"]}
APPサーバに/etc/systemd/system/docker.service.d/docker.conf
を作成、追記します。
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd
設定を変更したのでAPPサーバのDockerを再起動します。
systemctl restart docker
警告
-H オプションを使うと、Docker デーモンは指定した IP アドレスとポートをリッスンします(ポートを開きます)。標準では、unix:///var/run/docker.sock をリッスンし、ローカルの root ユーザのみ接続できます。これを 0.0.0.0:2375 や特定のホスト IP を指定することで、誰でもアクセス可能にできましたが、推奨されていません。理由は、デーモンが稼働しているホスト上の root アクセスを誰もが簡単に得られるためです。
UIサーバ上にHTML,PHPのファイルを配置
UIサーバ上にコンテナ作成用のボタンを配置します。
(最低限の機能実装なので、必要に応じて追記してください。)
UIサーバに/var/www/html/index.html
を作成、追記
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>APIにpostリクエストを送信する</title>
</head>
<body>
<form action="post.php" method="post">
<button type="submit" name="create">作成</button><br>
</form>
</body>
</html>
UIサーバに/var/www/html/post.php
を作成、追記します。
<?php
$url = 'http://${APIサーバのIP}/api.php';
$data = array(
'name' => 'test'
'image' => 'httpd',
);
$context = array(
'http' => array(
'method' => 'POST',
'header' => implode("\r\n", array('Content-Type: application/x-www-form-urlencoded',)),
'content' => http_build_query($data),
)
);
$html = file_get_contents($url, false, stream_context_create($context));
echo $html . "<br>";
echo "コンテナを作成しました";
APIサーバ上にPHPのファイルを配置
UIサーバで「作成」ボタンを押すと送信されるPOSTリクエストを処理するためのプログラムを作成、配置します。
APIサーバに/var/www/html/api.php
を作成、追記します。
<?php
$cmd = "docker -H ${APPサーバのIP} run -d -p 8080:80 --name " . escapeshellarg($_POST['name']) . ' ' . escapeshellarg($_POST['image']) . ":latest";
echo exec($cmd) . "\n";
このプログラムが動くことでAPPサーバ上にコンテナが立ち上がります。(今回はApacheのコンテナ)
APPサーバ上に使いたいコンテナイメージを入れる
今回はApacheのコンテナを動かしたいので事前にhttpdのイメージを入れておきます。
docker pull httpd
これですべて準備が完了したはずです。
動作確認
ブラウザからUIサーバにアクセスします。
「作成」ボタンが表示されます。
そのボタンをクリックします。
コンテナが作成されます。
作成されたコンテナにアクセスしてみます。
APPサーバ上に作成されているのでAPPサーバの8080番ポートにブラウザからアクセスします。
Apacheが動いていることが確認できました。
一応APPサーバの裏側でもちゃんと動いているか確認します。
[root@app ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6387a999e61f httpd:latest "httpd-foreground" 6 minutes ago Up 6 minutes 0.0.0.0:8080->80/tcp, :::8080->80/tcp test
ちゃんと動いていることが確認できました。
方法2
APPサーバのDockerをDockerAPIで直接叩けるように設定
APPサーバのDockerをDockerAPIで直接叩けるように設定します。
APPサーバに/etc/docker/daemon.json
を作成、追記します。
{"hosts": ["unix:///var/run/docker.sock", "tcp://127.0.0.1:2375"]}
APPサーバに/etc/systemd/system/docker.service.d/docker.conf
を作成、追記します。
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd
設定を変更したのでAPPサーバのDockerを再起動します。
systemctl restart docker
UIサーバ上にHTML,PHPのファイルを配置
UIサーバ上にコンテナ作成用のボタンを配置します。
(最低限の機能実装なので、必要に応じて追記してください。)
UIサーバに/var/www/html/index.htmlを作成、追記
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>APIにpostリクエストを送信する</title>
</head>
<body>
<form action="post.php" method="post">
<button type="submit" name="create">作成</button><br>
</form>
</body>
</html>
UIサーバに/var/www/html/post.php
を作成、追記します。
<?php
$url = 'http://${APIサーバのIP}/api_post.php';
$data = array(
'name' => 'test',
'image' => 'httpd',
);
$context = array(
'http' => array(
'method' => 'POST',
'header' => implode("\r\n", array('Content-Type: application/x-www-form-urlencoded',)),
'content' => http_build_query($data),
)
);
$html = file_get_contents($url, false, stream_context_create($context));
echo $html . "<br>";
echo "コンテナを作成しました";
APIサーバ上にPHPのファイルを配置
APIサーバ上にUIサーバから来たPOSTをAPPサーバにPOSTするPHPファイルを配置します。
(APIサーバを飛ばして直接UIサーバからAPPサーバにPOSTを送りつけても大丈夫です。)
APIサーバに/var/www/html/api_post.php
を作成、追記します。
<?php
$url = 'http://${APPサーバのIP}/run.php';
$data = array(
'name' => "{$_POST['name']}",
'image' => "{$_POST['image']}",
);
$context = array(
'http' => array(
'method' => 'POST',
'header' => implode("\r\n", array('Content-Type: application/x-www-form-urlencoded',)),
'content' => http_build_query($data),
)
);
$html = file_get_contents($url, false, stream_context_create($context));
echo $html;
APPサーバ上にPHPのファイルを配置
APPサーバ上にAPIサーバから来たPOSTを受け取り、Dockerコンテナを起動するためのPHPファイルを配置します。
APPサーバに/var/www/html/run.php
を作成、追記します。
<?php
$data = array(
'name' => $_POST['name'],
'image' => $_POST['image'],
);
// create
$url = sprintf('http://127.0.0.1:2375/v1.41/containers/create?name=%s',
urlencode($data['name'])
);
$context = array(
'http' => array(
'method' => 'POST',
'header' => implode("\r\n", array('Content-Type: application/json',)),
'content' => json_encode(array(
'Image' => $data['image'],
'HostConfig' => array(
'PortBindings' => array(
'80/tcp' => array(
array('HostPort' => '10080')
)
)
)
))
)
);
$res = file_get_contents($url, false, stream_context_create($context));
echo $res;
// start
$url = sprintf('http://127.0.0.1:2375/v1.41/containers/%s/start',
urlencode($data['name'])
);
$context = array(
'http' => array(
'method' => 'POST'
)
);
$res = file_get_contents($url, false, stream_context_create($context));
echo $res;
このプログラムが動くことでDockerコンテナが起動します。
少し説明します。
DockerはDockerコマンドを叩く以外にも、DockerAPIで叩くこともできます。(詳細は参考サイトを読んで下さい。)
// create
の部分ではコンテナの作成コマンドを叩いています。いわゆるdocker create
ですね。
// start
の部分ではコンテナ起動のコマンドを叩いています。いわゆるdocker start
です。
わざわざDockerコマンドではなく、DockerAPIで叩いているのは、Dockerコマンドを直接叩こうとするとroot権限が必要になるため、スクリプトでは叩けません。
なのでDockerAPIで直接叩いています。
参考
Docker Engine API について
Docker Engine SDK および Docker API の利用例
APPサーバ上に使いたいコンテナイメージを入れる
今回はApacheのコンテナを動かしたいので事前にhttpdのイメージを入れておきます。
docker pull httpd
これですべて準備が完了したはずです。
動作確認
ブラウザからUIサーバにアクセスします。
「作成」ボタンが表示されます。
そのボタンをクリックします。
コンテナが作成されます。
作成されたコンテナにアクセスしてみます。
APPサーバ上に作成されているのでAPPサーバの8080番ポートにブラウザからアクセスします。
Apacheが動いていることが確認できました。
一応APPサーバの裏側でもちゃんと動いているか確認します。
[root@app html]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cd441a666d14 httpd "httpd-foreground" 6 seconds ago Up 5 seconds 0.0.0.0:8080->80/tcp, :::8080->80/tcp test
ちゃんと動いていることが確認できました。
まとめ
- ブラウザ(chromeやfirefoxなど)から「コンテナ作成」のボタンを押すと、裏で動いているサーバ上にDockerコンテナが作成された
- ブラウザから作成したコンテナにアクセスできた
おわりに
この記事は富士通クラウドテクノロジーズ Advent Calendar 2022 の15日目の記事でした。
明日は@ktakaakiさんのITエンジニアがレザークラフトを真面目にやってみたです。
洋服とか靴とか財布とか、革製品がマイブームなのでとても楽しみです!
この記事は必要最低限の動作をするシステムですので、必要に応じて改良してください。
誰かの役に立てば幸いです。
最後まで読んでいただきありがとうございました。