Code for final

ふぁいなる向けのコード置き場です。すでにコードじゃないこともいっぱい。

Electron + Vue.js + TypeScriptでWindowsアプリ開発環境を構築する手順(2020年版)

アプリを開発したくなり、前から気になってたElectronで作ってみようと調べてたらVue.jsが使えることがわかり、 アプリの開発環境を構築ようとしたものの、思いのほかつまづいたので対処方法をメモっときます。
たぶん時が流れると状況は変わってくると思うので2020年現在の手順と理解ください。

Electronとは

web(HTML+CSS)の技術でデスクトップアプリを作成できるフレームワークです。
ちなみにVisual Studo CodeはElectronでできています。

www.electronjs.org

Node.jsをインストール

現時点で推奨版となっている12.18をダウンロードしてインストールします。
インストールは次へ次へでOKです。

nodejs.org

Visual Studio Codeをインストール

すでに入っているひとはスキップでOKです。

code.visualstudio.com

VueCLIをインストール

Vue CLIはVue.jsで開発するのにほぼ必須なツールです。 Visual Studio Codeを起動してターミナルを開いて以下のコマンドを実行する。

>npm install -g @vue/cli

vue uiを実行

vue uiはプロジェクトの作成やプラグインのインストール、ビルドなどをGUIで行えるようになる便利なツールです。
Vue CLIに同梱されていますので別途インストールは不要です。
Vue CLIインストールが終わったら以下のコマンドをたたいてvue uiを起動します。

>vue ui

ここで以下のエラーがでました。

PS C:\Users\final> vue ui
vue : このシステムではスクリプトの実行が無効になっているため、ファイル C:\Users\final\AppData\Roaming\npm\vue.ps1 を読み込むことができま
せん。詳細については、「about_Execution_Policies」(https://go.microsoft.com/fwlink/?LinkID=135170) を参照してください。
発生場所 行:1 文字:1
+ vue ui
+ ~~~
    + CategoryInfo          : セキュリティ エラー: (: ) []、PSSecurityException
    + FullyQualifiedErrorId : UnauthorizedAccess

1年くらい前まではこんなエラー出なかったんですが、任意のコードが実行されないようにOSのセキュリティが厳しくなったんだと思います。 対処としてPowerShellを管理者権限で別に起動して以下のコマンドを実行します。

>PowerShell Set-ExecutionPolicy RemoteSigned

実行後は"vue ui"が成功すると思います。

vue uiでプロジェクトを作成

プロジェクトの作成は以下の記載の手順と同じ内容でOKです。

final.hateblo.jp

今回はテストを除いて以下を選択しました。ElectronでもTypeScriptは強く推奨します。

  • Babel
  • TypeScript
  • Router
  • Linter / Formatter

ただ、そのまま進めると以下のようなエラーが出てプロジェクト作成に失敗しました。

エラーの内容は以下のような感じで原因がさっぱりです。
1年くらい前は同じ手順で問題なく動いていたんですけどね。

at makeError (C:\Users\final\AppData\Roaming\npm\node_modules\@vue\cli\node_modules\execa\index.js:174:9)
    at C:\Users\final\AppData\Roaming\npm\node_modules\@vue\cli\node_modules\execa\index.js:278:16
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
    at async C:\Users\final\AppData\Roaming\npm\node_modules\@vue\cli\node_modules\@vue\cli-ui\apollo-server\connectors\projects.js:345:5    at async Object.wrap (C:\Users\final\AppData\Roaming\npm\node_modules\@vue\cli\node_modules\@vue\cli-ui\apollo-server\connectors\progress.js:39:14) {

海外の掲示板にyarnが入っていないのが悪いみたいなことが書いてあったので以下のコマンドを実行してから再度作成したらうまくいきました。
ちなみにyarnはnpmの後継みたいなコマンドです。

>npm install -g yarn

Electron用のプラグインを追加する

いよいよElectronの導入です。上記までの手順は通常のVue.jsの開発と同じです。
vue uiのプラグイン追加で、"electron-builder"を検索してプラグインをインストールします。
検索すると何個か出てきますが、一番上のダウンロード数が一番多いやつを選択します。 これもそのまま進めるとエラーになりました。(エラーメッセージは出ず何度やってもプラグインがインストールできない)

そこで一旦、vscodeを終了します。
vscodeを起動して、vueプロジェクトのフォルダを開きます。
ターミナルを開いてvue uiを起動する。
もっかいプラグインを追加する。
とうまくいきました。
Electronのバージョンはデフォルトのままで9.0を選択します。

アプリを起動

vue uiのタスクに”electron:serve”があるのでそれを実行するとアプリが起動します。

f:id:finalstream:20200603134224p:plain

途中、出力欄に赤いものが見えるかもしれませんが、起動はできました。

exeを作成

アプリを作ったらexeを配布する必要があります。
タスクの一覧にある"electron:build"を選択します。
パラメータで"Build for Windows"をONにします。
あとはタスクを実行します。

するとエラーになります。ビルドだとエラーがあると成功しないようになっており、アプリ起動するときに出てたエラーが邪魔をするわけです。
エラーはたくさん出てますが、以下のようなエラーがでていました。

ERROR in d:/finalstream/newdev/edc/node_modules/electron/electron.d.ts(1659,31):
1659:31 Cannot extend an interface 'NodeJS.EventEmitter'. Did you mean 'implements'?

これも日本のサイトに情報がなかったので公式のissueに確認すると、”@types/node”パッケージがv13以降だとエラーになるみたいなことが書いてありました。

github.com

”yarn list --depth=0”コマンドでインストールされているバージョンを確認すると"@types/node@14.0.9"となっていました。
どうやらVue CLIでインストールすると最新のバージョンが入るみたいです。
これでは現時点では動かないので以下のコマンドをvscodeのターミナルで実行してダウングレードします。
バージョンはv12系ならなんでもいいと思うので、現時点のv12系の最新版にします。

www.npmjs.com

 >yarn upgrade @types/node@12.*

それでもっかいビルドするとエラーがなくなると思いきや、1個残りました。

ERROR in d:/finalstream/newdev/edc/src/background.ts(27,7):
27:7 Type 'string' is not assignable to type 'boolean | undefined'.
    25 |       // Use pluginOptions.nodeIntegration, leave this alone
    26 |       // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
  > 27 |       nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION
       |       ^
    28 |     }
    29 |   });
    30 | 

エラーを見る限り、booleanに変換しろとのことなので、background.tsの該当箇所を以下のように修正します。"!!"つけてbooleanに変換します。

nodeIntegration: !!process.env.ELECTRON_NODE_INTEGRATION

これでビルドができました。
ビルドしたものはプロジェクトフォルダの"dist_electron"にできます。
デフォルトでインストーラも作ってくれるみたいですね。
インストーラが不要な方は"win-unpacked"フォルダの中を配布すればOKかと思います。
サンプルまんまのアプリですが、100MBくらいとサイズがでかいですね。
vscodeも確認しましたが、同じような感じだったのでElectronアプリはそんな感じなんだと思います。
いまの時代、100MBなんて数秒でダウンロードできるので問題ないですね。

最後に

以上でアプリの開発環境ができました。
これからアプリを作ってつまづきポイントがあればまた記録したいと思います。

Docker Desktopで複数のコンテナが連携したアプリ(WordPress)を構築するポイント

先日、Dockerを使ったコマンドだけでコンテナを構築する記事をまとめましたが、今回はファイルからコンテナを構築するポイントをまとめたいと思います。

複数のコンテナを同時に構築するのは"docker-compose"コマンドを使う

Dockerを調べたらよく見かける、"docker-compose.yml"や"Dockerfile"ですが、ファイルでコンテナを構築する場合はこれらのファイルと"docker-compose"というコマンドを使用します。
このコマンドはDockerDesktopをインストールしたら入っているので別途なにかを入れる必要はありません。

DockerでWordpressを構築してみる

WEBアプリはwebサーバー + php + mysqlで構築されているものも多いですが、 その代表的なアプリとしてブログのWordPressがあります。
そのWordPressをDockerで構築し、ポイントをまとめたいと思います。

以下の手順に沿って行えば構築できますが、ファイルを作成する時間もとれないひとは完成形のベースフォルダをGithubにあげましたので、 wordpressのダウンロードしてファイルを配置して"docker compose up -d"コマンドをたたけば構築できます。
apache + php + mysqlのベース環境としても使用していただけると思います。

github.com

ベースフォルダを作成

どこでもいいのでベースフォルダを作成します。 このフォルダ名は作成されるコンテナのプレフィックスとなります。 今回は"wordpress"という名称にします。

docker-compose.ymlを作成

ベースフォルダの中に"docker-compose.yml"ファイルを作成します。 中身は以下を貼り付けてください。

version: '3.7'

services:
  mysql: # MySQLサービス名
    image: mysql:5.7 # dockerhubのイメージ名
    volumes:
      - mysql_data:/var/lib/mysql # mysql_dataというボリューム名でMySQLのデータを保存
      - .\mysql\initdb.d:/docker-entrypoint-initdb.d # 構築後に実行するSQLを配置(オプション)
      #- ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf # MySQLの設定ファイル(オプション)
    restart: always # コンテナに連動して自動起動
    ports:
      - "3306:3306" # Windows側ポート:Linux側ポート
    environment:
      MYSQL_ROOT_PASSWORD: "password" # MySQLのrootユーザのパスワード

  php-apache: # phpのサービス名
    build: .\php # phpフォルダにあるDockerfileでビルド
    volumes:
      - .\htdocs:/var/www/html # htdocsフォルダをapacheのルートディレクトリにマッピング
    restart: always
    ports:
      - "80:80"
    depends_on:
      - mysql

  phpmyadmin: # phpmyadminサービス名
    image: phpmyadmin/phpmyadmin
    environment:
      PMA_HOST: mysql # MySQLのサービス名を指定
    restart: always
    ports:
      - "8080:80"
    depends_on:
      - mysql # MySQLが起動終わってから起動

volumes:
    mysql_data: {}  # mysql_dataという名前でボリュームを作成。{}は空って意味かな。

yaml形式というあまり見慣れない記述だと思いますが、xmljsonと同様でデータ構造を記述する言語です。
jsonに近い感じですが、インデントで階層を表現するため、括弧がないのとコメント(#)が記述できるのが異なる点ですかね。ちなみに先頭の"-"は配列を表します。

内容をさっくり説明すると、dbサーバ(mysql)とphpmyadminサーバとwebサーバ(apache+php)の3つコンテナを同時に作成する内容になっています。
wordpress構築にあたってphpmyadminは必須ではないですが、phpmysqlを扱うならほぼ必須なものなのでついでに追加しています。 servicesでそれぞれに名前をつけてコンテナを定義しています。
個々の定義でイメージ、ホストフォルダとのマッピング、ポートマッピング、依存関係などを設定します。
volumesで”mysql_data”を定義しているのはこれは外付けhddみたいなもので、コンテナ内にデータを置いておくとコンテナを削除したときにデータが消えるので、ボリュームとして保存しています。
今回はmysqlのデータファイルをマッピングしてその部分だけを保存する設定としています。

最低限これだけ知っていれば問題ないと思いますが、ほかにもいろんな設定ができるので、気になるひとは以下のドキュメントを参照してください。

docs.docker.jp

mysqlのコンテナ作成時にデータベースを構築する

mysqlのコンテナ構築後はデータベースが作成されていないのでそのままだとアプリで使用できません。
構築したmysqlに接続し、データベースを作成後にテーブルを作成、その後データをインポートするSQLを実行すればよいのですが、そのSQLを構築時に実行する設定ができます。
コンテナ内の"/docker-entrypoint-initdb.d"にsqlを格納することで構築後に実行されるという仕組みです。

sqlファイルを格納するため、"wordpress"フォルダの中に"mysql"フォルダを作成します。
mysql"フォルダの中に"initdb.d"フォルダを作成して、その中に"init_db.sql"を作成します。 中身は以下を貼り付けます。

CREATE DATABASE wordpress DEFAULT CHARACTER SET utf8;

wordpressに使用するデータベースを作成するSQLを記述しています。テーブルやデータはwordpressが作成してくれるので。

dockerfileでコンテナ構築後にコマンドを実行する

コンテナ構築後にコマンドを実行するには構築後にコンテナ内に入ってコマンドを叩けばOKなのですが、これも構築時にコマンドを実行することができます。
上記の"php-apache"コンテナだけ"image"の指定がないですが、代わりに"build"を指定しています。ここでDockerfileを使用します。Dockerfileはイメージをカスタマイズする際に使用する感じですかね。

"wordpress"フォルダの中に"php"フォルダを作成し、その中に"Dockerfile"を作成します。
中身は以下を貼り付けます。

# イメージを"php"でタグ"7.4-apache"で使う
FROM php:7.4-apache
# php.iniを置き換える(オプション)
# COPY ./php.ini /usr/local/etc/php/

# ライブラリをインストール(必要に応じて変更)
RUN apt-get update && apt-get install -y \
 libfreetype6-dev \
 libjpeg62-turbo-dev \
 libpng-dev \ 
 libonig-dev \
 && apt-get clean

# PHP拡張モジュールをインストール(必要に応じて変更)
RUN docker-php-ext-install pdo_mysql mysqli gd iconv

phpapacheがいっしょになったイメージを使っていますが、phpは外部のモジュールを入れて使うことが多いです。
そのため、apt-getコマンドで必要なライブラリをインストールしています。apt-getはcentosでいうとyumコマンドでパッケージを管理するコマンドです。
docker-php-ext-installコマンドはPHP拡張モジュールをインストールするコマンドです。

wordpressをダウンロードして配置する

wordpressは以下からダウンロードできます。

ja.wordpress.org

wordpressフォルダの中にhtdocsフォルダを作成し、そこに解凍してできた"wordpress"フォルダの中身をすべて移動します。
htdocsフォルダの中にindex.phpがある配置になります。

最終的に以下のようなフォルダ構成になっていればOKです。

wordpress
│  docker-compose.yml
│
├─htdocs
├─mysql
│  └─initdb.d
│          init_db.sql
│
└─php
        Dockerfile

docker-composeコマンドを実行して構築する

PowerShellで"wordpress"フォルダに移動して以下のコマンドを実行します。

>docker-compose up -d

上記のコマンドだけで構築が完了すると思います。
ちなみに以下のコマンドがでたら構築は終わっていますが、内部でサービスの起動とか走っているのでしばらくまったらつながるようになります。30sくらいまてばOKです。

Creating wordpress_mysql_1 ... done                                                                                     
Creating wordpress_phpmyadmin_1 ... done                                                                                
Creating wordpress_php-apache_1 ... done

ダッシュボードを開くと"wordpress"でグループ化されたコンポーネントが確認できると思います。

f:id:finalstream:20200520113802p:plain

最初にも記載しましたが、このグループ化された名称は"docker-compose.yml"があるフォルダ名で決まるのでフォルダ名はわかりやすく、重複しないようにつけたほうがいいです。

ログを確認する

以下のコマンドでログの確認ができます。

>docker-compose logs

ただ、ダッシュボードで確認したほうが、検索できるので便利です。

f:id:finalstream:20200520121534p:plain

たとえば、"entry"で検索すると、以下のような出力がされていればデータベース作成用のSQLが実行されていることが確認できます。

mysql_1 | 2020-05-17 15:10:43+00:00 [Note] [Entrypoint]: /usr/local/bin/docker-Entrypoint.sh: running /docker-Entrypoint-initdb.d/init_db.sql

wordpressにアクセスする

http://localhost/ にアクセスすると以下のwordpressへようこそ。という画面が表示されます。

f:id:finalstream:20200518164448p:plain

さあ、始めましょう!をクリックします。

データベースの接続情報を入力します。 以下のように入力します。 ポイントはホスト名は"localhost"でなく、コンテナのサービス名"mysql"を指定します。

f:id:finalstream:20200518164701p:plain

送信ボタンをクリックして以下の画面になればOKです。

f:id:finalstream:20200518164853p:plain

インストール実行をクリックする。

必要な情報をいれます。中身は自由でOKです。

f:id:finalstream:20200518170639p:plain

Wordpressをインストールをクリックする。

あとはそのまま続けてログインできれば構築完了です。

f:id:finalstream:20200518170855p:plain

よく使うdocker-composeコマンド

停止する。

>docker-compose stop

削除する。停止もされます。コンテナ内のデータが消えるので注意!(volumesでマッピングしている場合はコンテナ外にデータがあるので大丈夫です)

>docker-compose down

中に入ってコマンドをたたく。以下の"mysql”はサービス名を指定します。

>docker-compose exec mysql /bin/bash

まぁコマンド覚えなくてもぜんぶダッシュボードからなんとかなります。

あとファイルのコピーとかはdockerコマンドでできます。docker-composeは複数のコンテナをまとめて操作するコマンドで 個々のコンテナの操作はdockerコマンドという感じですかね。

nginx + MariaDBに載せ替える

今作った環境をMariaDBとnginxに載せ替えたいと思います。
"wordpress"フォルダをそのまま変更してもいいですし、コピーしてもいいです。
docker-compose.ymlを以下に編集します。

ersion: '3.7'

services:
  mysql: # MySQLサービス名
    image: mariadb # dockerhubのイメージ名
    volumes:
      - mysql_data:/var/lib/mysql # mysql_dataというボリューム名でMySQLのデータを保存
      - .\mysql\initdb.d:/docker-entrypoint-initdb.d # 構築後に実行するSQLを配置(オプション)
      #- ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf # MySQLの設定ファイル(オプション)
    restart: always # コンテナに連動して自動起動
    ports:
      - "3306:3306" # Windows側ポート:Linux側ポート
    environment:
      MYSQL_ROOT_PASSWORD: "password" # MySQLのrootユーザのパスワード

  web: # nginxのサービス名
    image: nginx
    volumes:
      - .\web\default.conf:/etc/nginx/conf.d/default.conf
      - .\htdocs:/var/www/html # htdocsフォルダをnginxのルートディレクトリにマッピング
    restart: always
    ports:
      - "80:80"
    depends_on:
      - mysql
      - app

  app: # phpのサービス名
    build: .\php # phpフォルダにあるDockerfileでビルド
    volumes:
      - .\htdocs:/var/www/html
    restart: always
    depends_on:
      - mysql

  phpmyadmin: # phpmyadminサービス名
    image: phpmyadmin/phpmyadmin
    environment:
      PMA_HOST: mysql # MySQLのサービス名を指定
    restart: always
    ports:
      - "8080:80"
    depends_on:
      - mysql # MySQLが起動終わってから起動

volumes:
    mysql_data: {}  # mysql_dataという名前でボリュームを作成。{}は空って意味かな。

apache + mysql版と変えたところは以下な感じです。

  • mysqlサービスのイメージ名を"mariadb"に変更(MariaDBMySQL互換なのでこれだけでOK)
  • php-apacheサービスを"web"と"app”に分割
  • nginx用の設定ファイルを追加

nginx用の設定ファイルは"wordpress"フォルダに"web"フォルダを作成し、"default.conf"を作成します。
中身は以下を貼り付けます。

server {
    listen 80;
    server_name _;
    root  /var/www/html;
    index index.php;

    access_log /var/log/nginx/access.log;
    error_log  /var/log/nginx/error.log;

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(\.+)$;
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

これで"docker-compose up -d"で起動すれば、nginx + MariaDBwordpressを構築完了です。

最後に

docker-composeを使うことでサーバ構築が楽になってアプリ開発に専念できそうです。
最後にnginx + MariaDBに変更しましたが、手軽にサーバ載せ替えとかできるんでこりゃ便利です。
XAMPPで構築するより融通がいろいろと効きそうですね。 Dockerについてこれで一通り知識がインプットできた気がします。
ほかにも便利な機能はあるかもなのであったらまた記録してきたいと思います。

Windows10にDocker Desktop for WindowsをいれてLinuxコンテナで動かす手順(実践編)

Dockerの導入について以下の記事で書きましたが、ただwebサーバーを立てただけで、コンテンツを更新したりする手順とかわからなく、 このままだと実務で使うときに苦労すると思ったので実務を想定して必要そうな知識をまとめたいと思います。
ここでいう実務は開発、テストを想定しています。本番で運用するためにはもっといろいろと知識が必要ですのでご注意を。

final.hateblo.jp

コンテンツを適用する方法は2つある

基本編ではwebサーバーを立てて"It Works!"が出て満足していましたが、実務ではコンテンツをサーバに配置する必要があります。
Dockerではその手順として2つあります。

  • コンテナ内のファイルを差し替える
  • ホストのフォルダをコンテナ内のフォルダとリンクする

後者だけ覚えておけばなんとかなりそうな気もしますが、テストとかだとコンテンツを配るのが面倒なときとかに使えそうな気はしますので両方説明します。

コンテナ内のファイルを差し替える

試しにapache webサーバーのindex.htmlを書き換えてみます。

まずコンテナ同士が別々に動作していることがわかるようにもう一個apacheのサーバを立てます。 名前とポートを変えれば何個でも作成可能です。

> docker run -d -p 8080:80 --name httpd2 httpd

"localhost:8080"でアクセスしたら"It works!"と表示されると思います。

ではこのhttpd2の方のLinux環境に入るには"docker exec"コマンドをたたいてください。 httpd2のところは入りたいコンテナ名を指定するだけであとはおまじないみたいなものです。

>docker exec -it httpd2 bash

すると以下のようになると思います。(@の右はコンテナIDでコンテナ作成時にランダムで生成されるので環境によって異なります)
sshでつないだときと同様にLinuxコマンドが実行できます。

root@4d11a0179bc4:/usr/local/apache2#

なのでapacheのindex.htmlファイルはhtdocsの下にあるので以下のコマンドで確認できます。

root@4d11a0179bc4:/usr/local/apache2# cd htdocs
root@4d11a0179bc4:/usr/local/apache2/htdocs# ls
index.html
root@4d11a0179bc4:/usr/local/apache2/htdocs# cat index.html
<html><body><h1>It works! </h1></body></html>

これを書き換えればいいのですが、viとかvimとか入っていないので、Windows環境から転送するしかないです。
Windows環境に戻るために"exit"をたたきます。そうするとWindowsに戻ります。

以下のコマンドを実行してワークディレクトリを作っておきます。

>cd c:\
>mkdir docker_work
>cd docker_work

まずは書き換えるためにコンテナ(Linux)内からWindowsにindex.htmlを持ってきます。 以下のコマンドを叩いて取得します。 "4d11a0179bc4"は各自のものに変えてください。先程のdocker execのとこからコピーすると確実かと思います。

>docker cp 4d11a0179bc4:/usr/local/apache2/htdocs .\htdocs

"docker cp"コマンドでホスト(Windows)とコンテナ(Linux)間のファイルやり取りができます。
cpコマンド同様、コピー元 コピー先で指定します。 コピー元のコンテナは"コンテナid:Linuxファイルパス"で指定します。
注意すべきところはコンテナ側のパスを指定するときはコンテナ名(httpd2)ではなく、コンテナIDを指定します。 コンテナIDは"docker exec"で接続するか"docker ps"で確認できます。

これで"c:\docker_work"にhtdocsフォルダができ、index.htmlが取得されたと思います。
index.htmlを自由に編集してください。

編集が終わったら次は以下のコマンドでコンテナ側にコピーします。
さっきと逆でコピー先がコンテナになります。

>docker cp .\htdocs 4d11a0179bc4:/usr/local/apache2

これで"localhost:8080"にアクセスすると表示される内容が変わったと思います。
"localhost"にアクセスしても"It works!"のままだと思います。
これでコンテナが別々の環境で動作していることがわかったと思います。 "localhost"を変えたい場合はhttpdのコンテナを同様に書き換えてみてください。

コンテナの状態をイメージとして保存する

コンテナをイメージとして保存することでいつでも"docker run"コマンドでコンテナを生成することができるようになります。
さきほどの"localhost:8080"の環境をイメージとして保存したいと思います。

httpd2の環境を保存するために以下の"docker commit"コマンドで状態を保存します。

>docker commit httpd2 httpdex:1.0

このコマンドの意味はhttpd2環境をhttpdexというイメージ名のタグ1.0で保存するという意味です。
以下のコマンドを実行して3台目のサーバを立てます。イメージにはいまほど作成した"httpdex:1.0"を指定します。

>docker run -d -p 8088:80 --name httpd3 httpdex:1.0

これで"localhost:8088"にアクセスするとhttpd2のコンテナ("localhost:8080")と同じ内容が表示されると思います。
これで"localhost:8080"の内容がイメージとして保存されてたということが確認できました。

ホストのフォルダをコンテナ内のフォルダとリンクする

さきほどのでコンテナ内のファイルを書き換えることができたと思いますが、これだと更新する度に書き換える必要があって、開発中は現実的ではないと思います。
コンテナ(Linux)がホスト(Windows)のフォルダを参照してくれるように設定することができます。

次に以下のコマンドを実行してさきほど保存したイメージ"httpdex:1.0"をベースに4台目のサーバを立てます。 ※実行時に共有フォルダに追加するかと聞かれると思いますが、”Share it”を選択してください。(キャンセルすると失敗します)

>docker run -v c:\docker_work\htdocs:/usr/local/apache2/htdocs  -d -p 8888:80 --name httpd4 httpdex:1.0

"localhost:8888"でアクセスするとhttpd3と同じ結果になると思いますが、ここで"c:\docker_work\htdocs"にあるindex.htmlを編集してください。
再度アクセスすると変更した内容が反映されていると思います。ほかのサーバーは変更されてないのも確認できると思います。
このように"docker run"実行時に"-v ホストのフォルダ(Windows):コンテナのパス(Linux)"を指定することでリンクできます。
ちなみに-vを複数個指定することもできるみたいです。

これで開発に耐えうる環境が構築できますね。

カスタマイズしたコンテナイメージを配布する

上記でカスタマイズしたコンテナイメージをほかの人にテストしてもらう場合、渡す必要があります。
その場合はファイルとして出力できます。

まず以下のコマンドを実行してコンテナイメージを確認しましょう。

>docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
httpdex             1.0                 379506f88e8f        21 hours ago        166MB
httpd               latest              b2c2ab6dcf2e        11 days ago         166MB

保存したイメージをファイルに出力するには"docker save"コマンドを実行します。 以下のコマンドで"httpdex:1.0"のイメージを出力します。

>docker save -o httpdex-1.0.tar httpdex:1.0

"httpdex-1.0.tar"が出力されますのでこのファイルをほかの人に渡して"docker load"コマンドを実行してイメージファイルを取り込んでもらいます。

>docker load -i httpdex-1.0.tar

あとはdocker runコマンドでイメージ名"httpdex:1.0"を指定してもらえばほかの人の端末にも同じ環境が構築されます。

複数のコンテナを連携したサービスを構築する

以下にまとめました。

final.hateblo.jp

最後に

ここに書いたのは基本的なことなので詳細は必要に応じて調べてみてください。
でわ、素敵なDockerライフを。