digdagServerの構築メモ
Centos7にdigdagサーバーを構築した際のメモ
久しぶりに自分のローカルPCにCentos7でサーバーを構築しようとしたが、 vagrant up しようとするとエラーが発生。。
下記組み合わせだとvagrant upがエラーする
D:\vagrant\labo>vagrant up The version of powershell currently installed on this host is less than the required minimum version. Please upgrade the installed version of powershell to the minimum required version and run the command again. Installed version: 2 Minimum required version: 3
上記エラーメッセージからPowerShellのバージョンを2系から3系以上に変更したが 次にWMF5.0(Windows Management Framework 5.0)をインストールする必要もあった。 詳細は以下のリンクから確認できる。
WMFのインストールが必要
digdagServerを構築する際にpostgreSQLを
- postgres9.6のインストールは以下のURLを参考にしてインストール
- CREATE EXTENSIONしないとエラーになるので注意
digdag_db=> CREATE EXTENSION "uuid-ossp"; ERROR: could not open extension control file "/usr/pgsql-9.6/share/extension/uuid-ossp.control": No such file or directory ## 拡張モジュールのインストールが必要 # yum -y install postgresql96-contrib.x86_64 ## postgresユーザーでログインして psql -U postgres -h 127.0.0.1 -d digdag_db CREATE EXTENSION "uuid-ossp";
postgre9.6 install
- https://qiita.com/purini-to/items/702565733a03c202d98e
- https://qiita.com/uhooi/items/44ed9370740c7521dce4
digdag/embulkのインストール
- java1.8がインストールされていることが前提
$ java -version openjdk version "1.8.0_151" OpenJDK Runtime Environment (build 1.8.0_151-b12) OpenJDK 64-Bit Server VM (build 25.151-b12, mixed mode) # インストールされていなければいれる $ yum -y install java-1.8.0-openjdk
# Embulkの導入 $ curl --create-dirs -o ~/bin/embulk -L https://dl.embulk.org/embulk-latest.jar $ chmod +x ~/bin/embulk # Digdagの導入 $ curl --create-dirs -o ~/bin/digdag -L "https://dl.digdag.io/digdag-latest" $ chmod +x ~/bin/digdag # OSX環境の場合は次のように.bash_profileを編集する $ cat << 'EOF' >> ~/.bash_profile # User specfic environment and startup programs export PATH=$PATH:$HOME/bin EOF $ source ~/.bash_profile
digdagはまりポイント
https://qiita.com/toyama0919/items/142d290c8dcb2c86851c
# vi /usr/lib/systemd/system/digdag.service [Unit] Description=digdag [Service] Type=simple PIDFile=/run/digdag.pid ExecStart="/usr/local/bin/digdag server -b 0.0.0.0 --config /opt/digdag/server.properties -O /opt/digdag/logs/tasklogs -A /opt/digdag/logs/accesslogs -L /opt/digdag/logs/server.log" User=root Group=root WorkingDirectory=/opt/digdag Restart=always RestartSec=5 KillMode=process TimeoutStopSec=1200 SyslogIdentifier=digdag [Install] WantedBy=multi-user.target
ExecStartは別ファイルにしないとエラーになるので注意
シェルは別ファイルにしないとエラーする
[Unit] Description=digdag [Service] Type=simple PIDFile=/run/digdag.pid ExecStart=/opt/digdag/start.sh User=root Group=root [Install] WantedBy=multi-user.target
https://qiita.com/cmwig65/items/3386a061aeb3d2f81b81 https://qiita.com/toyama0919/items/142d290c8dcb2c86851c https://qiita.com/bwtakacy/items/ec3151644512ca65f6b6
Go言語でJSONのデコード処理を検証してみた
GOでJSONをデコードする際の方法
GoでJSONを処理する最も一般的な方法
package main import "encoding/json" type Message struct { Name string Body string Time int64 } func main() { b := []byte(`{"Name":"Alice","Body":"Hello","Time":1294706395881547000}`) var m Message json.Unmarshal(b,&m) println(m.Name) // Alice println(m.Body) // Hello println(m.Time) // 1294706395881547000 }
- bとして定義されたJSONをjson.Unmarshalでデコード
- ポイントは、デコード結果を受け取るために構造体を定義している点
- 対象のJSONデータの構造を確認しつつ、実装時に構造体の定義を決める必要がある
複雑な構造のJSON処理で直面する問題
{ "took": 1, "timed_out": false, "_shards":{ "total" : 1, "successful" : 1, "failed" : 0 }, "hits":{ "total" : 1, "max_score": 1.3862944, "hits" : [ { "_index" : "twitter", "_type" : "tweet", "_id" : "0", "_score": 1.3862944, "_source" : { "user" : "kimchy", "message": "trying out Elasticsearch", "date" : "2009-11-15T14:12:12", "likes" : 0 } } ] } }
上記のJSONデータをデコードする処理を、単純にコーディングすると
package main import ( "encoding/json" "net/http" ) type ResultShards struct { Total int `json:"total"` Successful int `json:"successful"` Failed int `json:"failed"` } type ResultHitSource struct { User string `json:"user"` Message string `json:"message"` Date string `json:"date"` Likes int `json:"likes"` } type ResultHit struct { Index string `json:"_index"` Type string `json:"_type"` Id string `json:"_id"` Score float32 `json:"_score"` Source ResultHitSource `json:"_source"` } type ResultHits struct { Total int `json:"total"` MaxScore float32 `json:"max_score"` Hits []ResultHit `json:"hits"` } type Result struct { Took int `json:"took"` TimedOut bool `json:"timed_out"` Shards ResultShards `json:"_shards"` Hits ResultHits `json:"hits"` } func main() { resp, err := http.Get("http://127.0.0.1:9200/_search") if err != nil { panic(err) } defer resp.Body.Close() var result Result if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { panic(err) } println(result.Hits.Total) }
デコード結果格納までのコードの見通しをよくする
- 上記の例では、Goの平易な言語仕様しか用いていないために、見通しの悪い実装となっているのでリファクタリングする
- Goは構造体をネスト定義することが可能
- さらにネスト定義する構造体には型名が必要ないので、これも削除する
package main import ( "encoding/json" "net/http" ) type Result struct { Took int `json:"took"` TimedOut bool `json:"timed_out"` Shards struct { Total int `json:"total"` Successful int `json:"successful"` Failed int `json:"failed"` } `json:"_shards"` Hits struct { Total int `json:"total"` MaxScore float32 `json:"max_score"` Hits []struct { Index string `json:"_index"` Type string `json:"_type"` Id string `json:"_id"` Score float32 `json:"_score"` Source struct { User string `json:"user"` Message string `json:"message"` Date string `json:"date"` Likes int `json:"likes"` } `json:"_source"` } `json:"hits"` } `json:"hits"` } func main() { resp, err := http.Get("http://127.0.0.1:9200/_search") if err != nil { panic(err) } defer resp.Body.Close() var result Result if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { panic(err) } println(result.Hits.Total) }
- ネストに定義することで、本来のJSONの出力形式に見た目が近くなり、かつコード量も減る
発展的な実装テクニック
- 出力されるJSONの形式を完全に構造体でカバーする必要がなく、参照が必要なオブジェクトだけを構造体の定義でおさえるようにしても、デコード処理に支障は出ない
- ヒットしたドキュメントのリストのみを参照した場合は以下のように実装することができる
package main import ( "encoding/json" "net/http" ) func main() { resp, err := http.Get("http://127.0.0.1:9200/_search") if err != nil { panic(err) } defer resp.Body.Close() var result struct { Hits struct { Hits []struct { Source struct { Title string `json:"title"` Description string `json:"description"` ImageUrl string `json:"image_url"` Url string `json:"detail_url"` } `json:"_source"` } `json:"hits"` } `json:"hits"` } if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { panic(err) } for _, hit := range result.Hits.Hits { println(hit.Source.Title) println(hit.Source.Description) println(hit.Source.ImageUrl) println(hit.Source.Url) } }
- JSONデータに含まれるオブジェクトには、エラー情報のように「もしかしたら返却されるかもしれない」オブジェクトというものもあるので、こういった場合は対応するフィールドをポインタ型で用意するう
構造体定義の自動生成
- デコード結果を受け取る構造体の定義は、JSONデータから自動生成するWebアプリが公開されている
interfaceを利用して局所的に参照する
- 必要なオブジェクトをピンポイントに取り出す
- 各オブジェクトへのアクセスには型アサートを利用する
package main import ( "encoding/json" "net/http" ) func main() { resp, err := http.Get("http://127.0.0.1:9200/_search") if err != nil { panic(err) } defer resp.Body.Close() var result interface{} decoder := json.NewDecoder(resp.Body) if err := decoder.Decode(&result); err != nil { panic(err) } n, _ := result.(map[string]interface{})["hits"].(map[string]interface{})["total"].(float64) println(int(n)) // 359 // (int にキャストしなかった場合:+3.590000e+002) }
- JSONデータ内に検索結果として格納されている、ヒット件数の値を取り出しています
- 整数型はすべてfloat64として格納されているので、取得後にintにキャストする操作を行っている
Jasonライブラリ
- JasonというGitHub上で個人開発されているパッケージ
- GoのJSONライブラリの中では比較的なメジャーなもの
- 入れ子のオブジェクトを辿るためのインタフェイスも提供されていて、Jason を利用しない場合、型アサートを繰り返し記述することになりますが、これを簡略化して実装できる
package main import ( "github.com/antonholmquist/jason" "net/http" ) func main() { resp, err := http.Get("http://127.0.0.1:9200/_search") if err != nil { panic(err) } defer resp.Body.Close() v, err := jason.NewObjectFromReader(resp.Body) if err != nil { panic(err) } n, err := v.GetInt64("hits", "total") if err != nil { panic(err) } println(n) }
参考URL
- https://qiita.com/msh5/items/dc524e38073ed8e3831b
- https://stackoverflow.com/questions/21197239/decoding-json-in-golang-using-json-unmarshal-vs-json-newdecoder-decode
- http://kudohamu.hatenablog.com/entry/2014/11/05/165133
- https://qiita.com/nayuneko/items/2ec20ba69804e8bf7ca3
DecoderとUnmarshalの使い分け
- データがio.Readerストリームからのものである場合、またはデータストリームから複数の値をデコードする必要がある場合は、json.Decoderを使用します。
- すでにJSONデータがメモリにある場合は、json.Unmarshalを使用します。
Use json.Decoder if your data is coming from an io.Reader stream, or you need to decode multiple values from a stream of data.
Use json.Unmarshal if you already have the JSON data in memory.
Amazon S3に保存されているバケット毎のオブジェクト容量、オブジェクト数を知る方法は大きく分けて下記の2つの方法がある
AWS SAMを利用してGolangなLambdaをデプロイする
AWS CLIでデプロイ(Windows環境)
$ GOOS=linux go build -o main $ zip deployment.zip main
$ aws lambda create-function \ --region us-west-2 \ --function-name HelloFunction \ --zip-file fileb://./deployment.zip \ --runtime go1.x \ --tracing-config Mode=Active \ --role arn:aws:iam::account_id:role/role_name \ --handler main
aws lambda create-functionのオプション
https://docs.aws.amazon.com/cli/latest/reference/lambda/create-function.html
depoly方法
https://github.com/aws/aws-lambda-go https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/deploying-lambda-apps.html
AWS SAMを利用してLambdaをデプロイする(Mac環境)
- template.ymlのroleは指定する
テンプレート
$ cat template.yml AWSTemplateFormatVersion: "2010-09-09" Transform: 'AWS::Serverless-2016-10-31' Resources: App: Type: 'AWS::Serverless::Function' Properties: Handler: lambda-go-sample # ファイル名 Runtime: go1.x CodeUri: build # ビルドファイルの設置ディレクトリを設定 Role: arn:aws:iam::account_id:role/role_name # Roleを設定する Timeout: 1
デプロイ
$ GOARCH=amd64 GOOS=linux go build -o build/lambda-go-sample $ aws cloudformation package \ --template-file template.yml \ --s3-bucket <bucket-name> \ --s3-prefix lambda-go-sample \ --output-template-file .template.yml $ aws cloudformation deploy \ --template-file .template.yml \ --stack-name lambda-go-sample \ --capabilities CAPABILITY_IAM
実行結果
$ aws cloudformation describe-stack-resources --stack-name lambda-go-sample
実行
$ aws lambda invoke --function-name lambda-go-sample-App-xxxx --payload '"Lambda"' out.txt
Docker compose
- npmコマンドが使用できる必要あり
- docker-composeコマンドが使用できる必要あり
docker-compose.ymlファイルとは
docker-compose.yml
ファイルは以下のようにyaml形式でDockerコンテナに関する起動オプション(buildオプションも含まれることもある)を記述したファイル
docker-compose.ymlサンプル
web: build: . ports: - "5000:5000" volumes: - .:/code links: - redis redis: image: redis # yaml の記載方法については下記を参照 # https://docs.docker.com/compose/compose-file/
Docker Compose概要
Docker composeとは複数のコンテナから成るサービスを構築・実行する手順を自動的にし、管理を用意にする機能 Docker composeでは、composeファイルを用意してコマンドを1回実行することで、そのファイルから設定を読み込んで全てのコンテナサービスを起動することができる
Docker Composeを使うまでの主なステップ
- それぞれのコンテナのDockerfieを作成する(既にあるイメージを使う場合は不要)
- docker-compose.ymlを作成し、それぞれ独立したコンテナの起動定義を行う(場合によっては構築定義も含まれる)
docker-compose up
コマンドを実行してdocker-compose.ymlで定義したコンテナを開始する
動作確認を行う環境について
(Working dir) +- docker-compose.yml +- app-server/ +- Dockerfile +- src/ +- app.js
Docker composeを使用した簡単なサンプル
Docker composeを使用した複数コンテナでひとつのサービスを作成するサンプルを実施してみる redisを使用してアクセス数をカウントする簡単なアプリケーションを作成してみる
application側の作成
アプリケーション側はnode.jsを使用する nodeの公式レポジトリを使用するための、Dockerfileは以下のように簡単なもの
app-server/Dockerfile
FROM node:5 RUN npm -g install redis ENV NODE_APTH /usr/local/lib/mode_modules ENTRYPOINT ["node", "app.js"]
npm
はnode.jsのpackageを管理するためのツール
ENTRYPOINT ["node", "app.js"]は nodeコマンドの引数にapp.jsを渡している
Redis側の作成
Redis側のコンテナの作成を行うが、公式のRedisイメージを使用するため、Dockerfileは不要
Docker composeファイルの作成
アプリ側のnodeのアプリケーションとredis側のアプリケーションをbuild,runするための定義をdocker-coposeファイルに記載する
docker-compose.yml
nodeapp: build: "./app-server" container_name: "nodeapp" working_dir: "/usr/src/app" ports: - "10080:10080" volumes: - "$PWD/app-server/src:/usr/src/app" links: - "noderedis" noderedis: image: "redis:3" container_name: "noderedis"
nodeのアプリケーションが乗るコンテナは、Dockerfileからイメージをbuildしてそこからnodeappという名前のコンテナを起動する redisが乗るコンテナについては、DockerfileからイメージをせずDocker hubからpullしてきた公式イメージを利用し、そこからnoderedisという名前のコンテナを起動する
docker-compose.yml
ファイルのあるディレクトリ移動し、docker-compose up
コマンドを実行する
$ docker-compose up
動作確認
$ curl http://localhost:10080 You accessed here 1 times. $ curl http://localhost:10080 You accessed here 2 times.
docker-composeコマンドで作成されるイメージ名
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE wk_nodeapp latest c36a03206379 15 minutes ago 649MB redis 3 256639e384de 8 weeks ago 99.7MB node 5 12b4a63115bc 17 months ago 648MB $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9fa382e87f70 wk_nodeapp "node app.js" 15 minutes ago Up 15 minutes 0.0.0.0:10080->10080/tcp nodeapp dba91dafd516 redis:3 "docker-entrypoint.s…" 15 minutes ago Up 15 minutes 6379/tcp noderedis
docker-compose.yml
nodeapp: # <- サービス名 build: "./app-server" # <- Dockerfile のあるファイルの場所(Dockerfile のある場所。git リポジトリのURL も指定可能) container_name: "nodeapp" # <- コンテナ名。指定しなかった場合はDocker compose で勝手に決められる working_dir: "/usr/src/app" # <- コンテナ内のワーキングディレクトリ。docker run コマンドの-w/--workdir に相当 ports: # <- Expose するポート。docker run コマンドの-p/--publish に相当 - "10080:10080" volumes: # <- Bind mount するディレクトリ。volume。docker run コマンドの-v/--volume に相当 - "$PWD/app-server/src:/usr/src/app" links: # <- 他のコンテナと接続するときのコンテナ名。docker run コマンドの--link に相当 - "noderedis" noderedis: image: "redis:3" # <- イメージIDとtag container_name: "noderedis"
参考URL https://qiita.com/TsutomuNakamura/items/7e90e5efb36601c5bc8a
Docker Hubのオフィシャルイメージを使ったLAMP環境(Apache+PHP+MySQL)
PHP+Apacheのイメージをつかってみる
$ docker rund -d php:5.6-apache
PHP+ApacheのイメージをDocker Hubから取得し、コンテナを起動
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
php 5.6-apache 61a89dae852c 3 weeks ago 378MB
取得したイメージを一覧を表示する STATUSの欄がUpになっていれば起動
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0877ed1b4e88 php:5.6-apache "docker-php-entrypoi…" 5 minutes ago Up 5 minutes 80/tcp agitated_wright
ブラウザで確認する
上の方法では、起動しているコンテナのポートが内部で閉じているのでブラウザで確認することはできない。コンテナのポートを公開する
$ docker run -p 80:80 -d php:5.6-apache
-p
オプションでホストのポートとコンテナのポートを結びつける。コロンの左側がホスト側、右側がコンテナ側のポート番号。
コンテナを削除する
$ docker rm -f コンテナID
これで削除できる。コンテナIDは以下で確認できる
$ docker ps -a
コンテナを一括で全て削除することも可能
$ docker rm -f $(docker ps -a -q)
コンテナを作成する
1.コンテナに入ってファイルを作成する
$ docker run -p 80:80 --name php -d php:5.6-apache
分かりやすように、--name
オプションでコンテナにphp
という名前をつけている
$ docker exec -ti php bash
phpコンテナ内に入ることができる。-ti
をつけないとターミナルを開くことはできない
ドキュメントルートの/var/www/html
にいるはずなので、
# echo '<?php phpinfo();' > index.php
ブラウザでサーバーのURLを開きphpinfoの画面が確認できる
2.コンテナのディレクトリとホストのディレクトリを結びつける
コンテナは永続かされないので、コンテナを削除するとコンテナ内で作成したファイルも消えてしまう。ホスト側にファイルを置き、そのディレクトリをコンテナ側から参照する手法を試す
ホスト側のファイルを置くディレクトリは/Users/121799/docker/www
どこにおいても問題ない
以前のコンテナを削除してから、以下を実行する
$ docker run -p 80:80 -v /Users/121799/docker/www:/var/www/html --name php -d php:5.6-apache
-v
オプションでホストのディレクトリとコンテナのディレクトリを結びつける。コロンの左側がホスト側、右側がコンテナ側のディレクトリ。
MySQLのイメージを使ってみる
起動してコマンドラインから操作してみる
$ docker run --name mysql -e MYSQL_ROOT_PASSWORD=pass -d mysql:5.7
MySQL5.7のイメージをDocker Hubから取得し、起動する
-e
オプションは環境変数を設定するもので、root
のパスワードをpsss
に設定している
コンテナに入る MySQLの操作ができるようになる
$ docker exec -ti mysql bash $ mysql -ppass
PHPとMySQLの連携
DockerfileによるPHPイメージのカスタマイズ
オフィシャルのPHPコンテナは最小限のオプションでコンパイルされている。そのままではMySQLと連動するのが難しい。 Dockerfileを使うと、既にあるイメージをカスタマイズして新しいイメージを作ることができる
Dockerfileの場所はどこでも良い。今回は/docker/phpに作成する
ホスト側で/docker/php/Dockerfile
を以下の内容で作成する
FROM php:5.6-apache
RUN apt-get update && \
docker-php-ext-install pdo_mysql mysqli mbstring
FROMは元となるイメージを指定する
RUMコマンドを指定する。docker-php-ext-installはphp:5.6-apache
イメージに含まれるユーティリティで、オプションを追加してPHPをリコンパイルするもの
docker-php-ext-install
引数を元にエクステンションをインストールしてくれる
Dockerfileが用意できたら、新しいイメージをビルドする
docker build -t php:custom /docker/php
/docker/phpにあるDockerfileを元にphp:custom
というイメージを作成する。docker images
で確認する
MySQLイメージの設定を変更する
先ほど、作成したコンテナは削除しておく
Docker HubのMySQLイメージはcharacter setがlatin1になっている部分があるので設定ファイルを追加する /docker/mysql/custom.confを以下の内容で作成
[mysqld] character-set-server=utf8
$ docker run --name mysql -v /docker/mysql:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=pass -d mysql:5.7
-v
オプションでホスト側の/docker/mysqlディレクトリとコンテナ側の/etc/mysql/conf.dディレクトリを結びつけている
PHPコンテナをMySQLコンテナとリンクして起動する
$ docker run -p 80:80 -v /docker/www:/var/www/html --link mysql:mysql -name php -d php:custom
--link
オプションでコンテナmysqlを連携する。
コロンの左側にコンテナ名を指定する
連携が取れているか確認する
$ docker exec -ti php bash $ cat /etc/hosts172.17.0.2 mysql d5ca7e687d9b
--link
オプションで指定した名前でホスト名にアクセスできる
コロンの右側で指定した名前
phpMyAdminを導入して確認
連携の確認用にphpMyAdminをホスト側に導入
cd /docker/www wget https://files.phpmyadmin.net/phpMyAdmin/4.4.13.1/phpMyAdmin-4.4.13.1-all-languages.tar.gz tar zxf phpMyAdmin-4.4.13.1-all-languages.tar.gz rm phpMyAdmin-4.4.13.1-all-languages.tar.gz mv phpMyAdmin-4.4.13.1-all-languages myadmin cd myadmin/ cp config.sample.inc.php config.inc.php
config.inc.php
$cfg['Servers'][$i]['host'] = 'mysql'
hostをlocalhost
から--link
オプションにより設定されたホスト名mysql
に変更する
- http://localhost/myadmin
- ID:root
- PW:pass
DockerでPHP7.0 + Apacheの環境を構築する
PHP7.0 + Apacheを起動する
docker run -d -p 80:80 --name php70-apache php:7.0-apache
でイメージからコンテナを立ち上げる(ローカルにimageがない場合はDocker Hubから取得してくれる)
-p
オプションでポートを80番でフォワード
$ docker run -d -p 80:80 --name php70-apache php:7.0-apache Unable to find image 'php:7.0-apache' locally 7.0-apache: Pulling from library/php f49cf87b52c1: Pull complete 185616061386: Pull complete 5fc132db2e0d: Pull complete 00c1c323341a: Pull complete ff3701349211: Pull complete faab1d6ad70f: Pull complete eae8d88d75e0: Pull complete 7fbd4c732645: Pull complete b2e59bdd1208: Pull complete d5519147d4e5: Pull complete 512315391b1a: Pull complete b32d82403bad: Pull complete b5eb11551d42: Pull complete 02fee8125e6e: Pull complete Digest: sha256:6616fa9ab36d721c2e3e0e128295f474f1e6f5f7bd04207ce0dc50581ecd4073 Status: Downloaded newer image for php:7.0-apache f4821286b2156584088f0c29c6e09c6cc4b582c310b6449ca94892bb944e219f
Apacheが起動していることを確認
$ curl http://localhost/ <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>403 Forbidden</title> </head><body> <h1>Forbidden</h1> <p>You don't have permission to access / on this server.<br /> </p> <hr> <address>Apache/2.4.10 (Debian) Server at localhost Port 80</address> </body></html>
php70-apacheコンテナへログインする Forbiddenページしか表示されないので、実際にPHPを書いて表示させてみる
$ docker container exec -ti php70-apache bash $ echo '<?php phpinfo();' > index.php
ホスト⇄コンテナ間でディレクトリを同期する
コンテナを削除した際に同時にそのコンテナ内にあるファイルも消えてしまう
なので、ホスト側とコンテナのディレクトリを同期させて、そこにファイルを書き込む形式をとる
# コンテナを停止 $ docker container stop php70-apache # コンテナを削除 $ docker container rm php70-apache
新しく新しくディレクトリが同期されるコンテナを作成する
ホスト側の同期対象となるディレクトリ
/Users/121799/docker/php70-apache/www
コンテナ側はドキュメントルートである
/var/www/html
とする
$ docker run -d -p 80:80 -v /Users/121799/docker/php70-apache/www:/var/www/html --name php70-apache php:7.0-apache e78a1ac509425b8cf56ee2c0e988a5d5ec39eb539ea8ffefcced4a7ab6bcea76
/Users/121799/docker/php70-apache/www
にいる場合に
$echo '<?php phpinfo();' > index.php
これで再度、localhostにアクセスしてみる ホスト側で作成されたファイルがコンテナへ正しく同期されていることが確認できる
参考URL