created と mounted
どちらもVuejsが提供するライフサイクルフック。たいていのサンプルでは、このライフサイクルフックのどちらかでAPIアクセスをするが、どんな違いがあるんだろう。
created
- インスタンスの初期化が済んで props や computed にアクセスできる
- DOMにはアクセスできない
mounted
- created + DOMにアクセスできる
APIアクセスは created と mounted のどちらで行う?
APIアクセスはほとんどのライブラリで非同期に行われる。そのため、 created と mounted のどちらでAPIアクセスを開始しようが、レスポンスが返ってきた時点でコールバックが実行される。
上記を踏まえて、レスポンス完了後のコールバックの中で、
propsにデータを設定するだけの場合は、 created を使う
- DOMを構築してる間にも、HTTPの通信を行えるから
- DOMがでかいと、Edgeだと、mountedよりも体感できるレベルで早くなる
DOMにアクセスする必要があるときは、 mounted を使う
- レスポンスが即返ってきた場合に、DOMの構築が終わっていない可能性がある
- jQuery 時代をひきずったようなDOMを直接指定するライブラリを使うときはこっち
と良さそう。
検証環境
"dependencies": {
"axios": "^0.17.1",
"vue": "^2.5.2"
}
json serverを用意する
npm で json-server
をインストールし、起動する。
$ json-server --watch db.json
{
"users": [
{
"id": 1,
"name": "Stark"
},
{
"id": 2,
"name": "Targaryen"
},
{
"id": 3,
"name": "Tyrell"
}
]
}
サンプルを用意する
<template>
<section>
<h1>ユーザリスト</h1>
<ul>
<li v-for="user in users" :key="user.id">
{{user.name}}
</li>
</ul>
</section>
</template>
<script>
import Axios from 'axios'
export default {
name: 'Users',
data () {
return { users: [] }
},
created () {
const self = this
Axios.get('http://localhost:3000/users')
.then((res) => {
self.users = res.data
})
}
}
</script>
実行結果
- mounted が実行される
- usersが [] の状態でDOMが作られる(『ユーザリスト』のタイトルだけ先に表示される)
- レスポンスが返ってきたら users に値が設定される
- Vueが変更を検知してDOMが再構築される
参考
env_file
コンテナ内で利用できる環境変数を、外部ファイルから読み込める。この変数は、docker-compose.ymlからは利用できない。
$ cat app.env
SAMPLE_APP_VERSION=1.0.0
version: "3"
services:
app:
image: "alpine:latest"
env_file:
- app.env
command: env
$ docker-compose up
Recreating docker_app_1 ... done
Attaching to docker_app_1
app_1 | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
app_1 | HOSTNAME=6656d72f7508
app_1 | SAMPLE_APP_VERSION=1.0.0
app_1 | HOME=/root
docker-compose run -e XXX=YYY
コンテナ内で利用できる変数をdocker-composeの起動引数で設定できる。この変数は、docker-compose.ymlからは利用できない。
version: "3"
services:
app:
image: "alpine:latest"
command: env
$ docker-compose run -e SAMPLE_APP_VERSION=1 app
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=6ca4fb8fa3f4
TERM=xterm
SAMPLE_APP_VERSION=1
HOME=/root
変数の優先順位
コンテナ内の変数の優先順位
リファレンスの通り。
- Compose file,
- Environment file,
- Dockerfile,
- Variable is not defined.
docker-compose.yml で参照するときの優先順位
環境変数 > .envファイル
version: "3"
services:
app:
container_name: ${NAME}
image: "alpine:latest"
command: env
$ cat .env
NAME=hoge
$ export NAME=fuga
$ docker-compose up
Recreating hoge ... done
Attaching to fuga
fuga | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
fuga | HOSTNAME=68c4de49dd38
fuga | HOME=/root
fuga exited with code 0
動的な値を利用したい
docker-compose.yml
docker-compose.ymlで動的な値を利用したければ、docker-compose を実行する前に、環境変数を設定すれば良い。
version: "3"
services:
app:
container_name: "app-${ID}"
image: "alpine:latest"
command: env
$ export ID=$(date '+%Y%m%d')
$ docker-compose up
Creating app-20180311 ...
Creating app-20180311 ... done
Attaching to app-20180311
app-20180311 | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
app-20180311 | HOSTNAME=10df3a31c3ff
app-20180311 | HOME=/root
app-20180311 exited with code 0
Dockerコンテナ
Dockerコンテナで動的な値を利用したければ、environmentで環境変数を指定しておき、
version: "3"
services:
app:
image: "alpine:latest"
environment:
- TIMESTAMP
command: env
docker-compose 実行前に、環境変数を設定すれば良い。
$ export TIMESTAMP=$(date '+%Y%m%d')
$ docker-compose up
Recreating compose_app_1 ...
Recreating compose_app_1 ... done
Attaching to compose_app_1
app_1 | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
app_1 | HOSTNAME=4f2282348e06
app_1 | TIMESTAMP=20180311
app_1 | HOME=/root
あるいは、env_fileで読み込むファイルをdocker-compose実行前に作成する。
version: "3"
services:
app:
image: "alpine:latest"
env_file:
- app.env
command: env
$ cat > app.env << FIN
TIMESTAMP=$(date '+%Y%m%d')
FIN
$ docker-compose up
Starting compose_app_1 ...
Starting compose_app_1 ... done
Attaching to compose_app_1
app_1 | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
app_1 | HOSTNAME=4f2282348e06
app_1 | TIMESTAMP=20180311
app_1 | HOME=/root
compose_app_1 exited with code 0
参考
パケットキャプチャ
LBのeth0(クライアント側NIC)のパケットをキャプチャする。
# tcpdump port 80 -i eth0 -w eth0.pcap
LBのeth1(バックエンド側NIC)のパケットをキャプチャする。
# tcpdump port 80 -i eth1 -w eth1.pcap
上記から、LBで接続元IPや接続先IPの変換はするものの、TCPコネクションが1本しか張られていないことがわかる。(接続元のエフェメラルポート番号がそのまま接続先に渡されており、また、時刻から、LBはパケットを横流ししているようになっている)
MACアドレス変換方式(DSR方式)
構成図は以下のとおり。
以下を参考に、LBとしてipvsadm を利用する。
http://momijiame.tumblr.com/post/71390424576/centos-65-%E3%81%A7-lvs-ipvs-%E3%81%AE-direct-server-return
設定
LBでipvsadmの設定をする。
]# iptables -L
]# ipvsadm -A -t 192.168.11.107:80 -s lc
]# ipvsadm -a -t 192.168.11.107:80 -r 192.168.11.108:80 -g
]# ipvsadm -L
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.11.107:http lc
-> 192.168.11.108:http Route 1 0 0
次に、バックエンドサーバでhttpdを起動し、クライアントからHTTPリクエストを投げる。
パケットキャプチャ
LBのパケットをキャプチャする。
# tcpdump port not 22 -w lb.pcap
戻りパケットがLBを経由しないため、Wiresharkがパケットが欠けてると警告を出している。
バックエンドサーバのパケットをキャプチャする。
# tcpdump port 80 -w backend.pcap
接続先IPアドレスがLBのIPアドレスになっている。また、接続元IPアドレスがクライアントのアドレスになっている。
上記から、戻りパケットだけはLBを経由せずにクライアントにダイレクトに返っていることがわかる。まさにDirect Server Return…