docker-composeでNginx + Django + MySQLのWeb三階層を構成する
Kubernetesクラスタの構築方法など、インフラ観点での記事を書くことが多い本ブログですが、Kubernetesを学んでみると
- インフラエンジニアもアプリケーションエンジニアの気持ちがわかったほうがいい!
というお気持ちになるのです。CI/CDとか考えると特に。
そんなことでOSにも標準でインストールされている意味でメジャーな言語であるPythonを、そのWebフレームワークであるDjangoを通して勉強しているわけなのですが、DjangoでSQLiteとか、python manage.py runserver
とか使っていると、「本番環境だとこれどう変わるのん?」というインフラエンジニアならではの疑問が沸々と湧き上がってくるのです。
そこで、Pythonのお勉強のわき道にそれて、Nginx + Django + MySQLでWeb三階層を組んでみました。せっかくDockerコンテナのことも知っているので、docker-composeを使い、コンテナでWeb三階層を組んでみました。そのときのdocker-compose.yml
をさらしたいと思います。
いきなりdocker-compose.yml
をさらす前に、プロジェクトのディレクトリ構成を示しておきます。
. ├── docker-compose.yml ├── mysite ← Djangoプロジェクトのルート │ ├── Dockerfile チュートリアルアプリであるpollsアプリを作成 │ ├── docker-entrypoint.sh │ └── mysite │ ├── manage.py │ ├── mysite │ ├── polls │ └── static ├── mysql ← MySQLプロジェクトのルート │ └── Dockerfile mysql:5.7イメージを使うだけ └── nginx ← Nginxプロジェクトのルート ├── Dockerfile 基本的にはnginx:1.15.alpineを使うだけだが、 ├── docker-entrypoint.sh Djangoと連携するためのUWSGI接続設定を組み込む └── mysite_nginx.conf
この前提の下で、docker-compose.yml
は以下のように書きました。
version: '3' services: mysite: build: mysite image: bbrfkr0129/mysite environment: MYSQL_DATABASE: mysite MYSQL_USER: mysite MYSQL_PASSWORD: password MYSQL_HOSTNAME: mysql networks: - mysite mysql: build: mysql image: bbrfkr0129/mysql environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: mysite MYSQL_USER: mysite MYSQL_PASSWORD: password volumes: - "mysql_data:/var/lib/mysql" networks: - mysite nginx: build: nginx image: bbrfkr0129/nginx ports: - "80:80" environment: UWSGI_HOST: mysite volumes: - "./mysite/mysite/static:/static" networks: - mysite volumes: mysql_data: driver: local networks: mysite: driver: bridge
mysql
サービスは、公式の使い方に準拠しているので、説明を省きます。
mysite
サービスではDjangoをuWSGI接続で動作させます。バックエンドDBにMySQLを使うので、あらかじめsettings.py
にMySQL接続用のパラメータを置換用文字列で書き換えておき、コンテナ起動時にdocker-entrypoint.sh
の処理内で実際のパラメータに置換します。Dockerfile
、docker-entrypoint.sh
は以下のような感じです。
FROM python:3.6-alpine3.8 # install django uwsgi and PyMySQL RUN apk --no-cache --virtual .requirements add g++ make linux-headers && \ apk --no-cache add libffi-dev mysql-dev mysql-client && \ pip install Django uwsgi mysqlclient && rm -rf ~/.cache/pip && \ apk del .requirements # install mysite RUN mkdir /mysite COPY ./mysite/ /mysite/ WORKDIR /mysite EXPOSE 8001 COPY docker-entrypoint.sh /usr/bin/ ENTRYPOINT ["docker-entrypoint.sh"] CMD ["uwsgi", "--socket", ":8001", "--module", "mysite.wsgi"]
#!/bin/sh sed -i "s/MYSQL_DATABASE/$MYSQL_DATABASE/g" /mysite/mysite/settings.py sed -i "s/MYSQL_USER/$MYSQL_USER/g" /mysite/mysite/settings.py sed -i "s/MYSQL_PASSWORD/$MYSQL_PASSWORD/g" /mysite/mysite/settings.py sed -i "s/MYSQL_HOSTNAME/$MYSQL_HOSTNAME/g" /mysite/mysite/settings.py export connected="no" while [ $connected = "no" ] do mysql \ -u$MYSQL_USER -p$MYSQL_PASSWORD -h$MYSQL_HOSTNAME \ -e "show tables;" $MYSQL_DATABASE if [ $? -eq 0 ] ; then export connected="yes" fi sleep 1 done python manage.py makemigrations polls python manage.py migrate python manage.py shell -c "\ from django.contrib.auth import get_user_model;\ User = get_user_model();\ User.objects.create_superuser('admin', 'admin@example.com', 'admin')\ " exec "$@"
nginx
サービスでは基本的にnginx:1.15-alpine
イメージを使いますが、DjangoのuWSGIに接続するための情報が必要なので、このための設定ファイルをdocker buildで埋め込み、コンテナ起動時にdocker-entrypoint.sh
の処理内でパラメータに置換します。Dockerfile
、mysite_nginx.conf
、docker-entrypoint.sh
は以下のような感じです。
# the upstream component nginx needs to connect to upstream django { # server unix:///mysite/mysite.sock; # for a file socket server UWSGI_HOST:8001; # for a web port socket (we'll use this first) } # configuration of the server server { # the port your site will be served on listen 80; # the domain name it will serve for server_name example.com; # substitute your machine's IP address or FQDN charset utf-8; # max upload size client_max_body_size 75M; # adjust to taste location /static { alias /static; } # Finally, send all non-media requests to the Django server. location / { uwsgi_pass django; include /etc/nginx/uwsgi_params; # the uwsgi_params file you installed } }
FROM nginx:1.15-alpine RUN rm -f /etc/nginx/conf.d/* COPY mysite_nginx.conf /etc/nginx/conf.d/mysite_nginx.conf COPY docker-entrypoint.sh /usr/bin/ RUN chmod 755 /usr/bin/docker-entrypoint.sh RUN mkdir /static ENTRYPOINT ["docker-entrypoint.sh"] CMD ["nginx", "-g", "daemon off;"]
#!/bin/sh sed -i "s/UWSGI_HOST/$UWSGI_HOST/g" /etc/nginx/conf.d/mysite_nginx.conf exec "$@"
Webサービスを起動するときは以下のコマンドを叩けばOKです。上がったらhttp://localhost/admin|でDjangoの管理者サイトにアクセスできるはずです。
docker-compose up -d
すべてきれいさっぱり消すときは...(永続データも消えるのでちゅうい)
docker-compose down -v
Docker for WindowsでMySQLコンテナのデータを永続化する
Docker for WindowsでMySQLコンテナのデータを永続化する際、ホストディレクトリを/var/lib/mysql
に単純にマウントすると、MySQLコンテナ側で以下のようなエラーが出ます。
2018-11-18T10:02:32.761277Z 1 [ERROR] [MY-012646] [InnoDB] File ./ibdata1: 'open' returned OS error 71. Cannot continue operation
このエラーを回避するにはDockerボリュームを使ってデータを永続化すると、うまくいくみたいです。具体的にはdocker-compose.yml
に以下のように記載して起動するとうまくいきます。
version: '3' services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: mydb MYSQL_USER: myuser MYSQL_PASSWORD: password volumes: - "mysql_data:/var/lib/mysql" volumes: mysql_data: driver: local
既定のアプリをコマンドで変更する方法
Windows 10の10月24日のアップデートでGUI上から一部の既定のアプリを変更することができないようになっているみたいです。これに見事にはまり、.txt
ファイルの既定のアプリをメモ帳から変更できなくなってしまいました。。。
Microsoft側もこのことを認識しており、11月下旬に向けて修正を予定しているようです。 https://support.microsoft.com/en-us/help/4462933/windows-10-update-kb4462933
Symptom | Workaround |
---|---|
After installing this update, some users cannot set Win32 program defaults for certain app and file type combinations using the Open with… command or Settings > Apps > Default apps. In some cases, Microsoft Notepad or other Win32 programs cannot be set as the default. | In some cases, attempting to set application defaults again will succeed. Microsoft is working on a resolution and estimates a solution will be available in late November 2018. |
11月下旬まで待ってられるか!という人は以下のようにして変更できるみたいです。
ftype txtfile="<テキストエディタのパス>" "%1"
OpenStackとoVirtで自宅クラウド環境を構築してみた
お久しぶりです。4か月間ぐらい全くポストしていませんでしたが生きています。
何やっていたかというと、自宅環境をOpenStackによってプライベートクラウド化しておりました。これが完成しないと諸々の検証ができないので、ブログのポストより優先していたら4か月も経っていた感じです。
4か月間にためていたナレッジは少しずつ文章にしていくつもりですが、まずはどんなプライベートクラウド環境を構築していたのか紹介する記事を書こうと思います。自宅環境を構築したい人、している人の少しでも参考になれば幸いです。
目的
本プライベートクラウド環境の目的ですが、以下の通りです。
- 製品の検証(主にインフラの検証。ハイパバイザレベルでの検証も含む)
- サービス提供(Wikiサイトなど)
従来はoVirtというOSSの仮想化基盤製品でこれらの目的をこなしていたわけですが、プライベートクラウド化することによって次のことを狙っていました。
- 様々なサービスのAPIコールによるデプロイ
oVirtはあくまで仮想化基盤なので、あくまでもAmazon EC2やEBS相当の機能しか提供してくれません。昨今のクラウドネイティブなアーキテクチャの学習には不向きだったのです。またコンテナ中核技術であるKubernetesの利便性を最大限引き出すにはクラウドとの連携は必須となります。このためOpenStackによって自宅IaaSを構築しようという考えに至りました。
ただし、OpenStackでは柔軟な仮想マシン設定を行うことが難しくなり、KVMなどのハイパバイザレベルでの動作検証が難しくなります。したがって検証環境すべてをOpenStackに移行したわけではなく、一部リソースをoVirt用に残すようにしました。
アーキテクチャ(物理)
物理構成は以下の通りになります。OpenStack Controllerはロードバランサなどの補助サーバはoVirt上のVMとして構築します。
- Intel NUC Pentiumモデル x 1 (oVirt Engine用)
- Intel NUC Corei3モデル x 3 (oVirt Node用)
- Intel NUC Corei3モデル x 3 (OpenStack Compute用)
アーキテクチャ(仮想)
VMを含めた構成は以下の通りです。冗長化による性能向上を狙って、OpenStack環境はActive/Activeクラスタを構成しています。(Cinder Volumeを除く)
構築したサービス
本プライベートクラウドでは以下のIaaSサービスを提供しています。
oVirt
通常の仮想化環境を提供します。KVM等のハイパバイザ自体を検証したいときはこっちを使います。VMやボリュームのプロビジョニングを行うことができ、通常の仮想化環境といってもAPIがついているので、Ansible等を用いてプロビジョニングを自動化することが可能です。OpenStack Keystone
AWSにおけるIAM相当の認証基盤を提供します。OpenStack Swift
AWSにおけるS3相当のオブジェクトストレージ機能を提供します。OpenStack Glance
AWSにおけるAMI相当のVMイメージストア機能を提供します。Swiftと連携してイメージをSwiftに保存するようにしています。OpenStack Neutron
AWSにおけるVPC、ELB相当の仮想ネットワーク、ソフトウェアロードバランサー機能を提供します。OpenStack Heat
AWSにおけるCloudFormation相当のオーケストレーション機能を提供します。OpenStack Magnum
AWSにおけるECS、EKS相当のコンテナオーケストレーション機能を提供します。Kubernetesのデプロイを一発で行えます。
まとめ
OSSを使って自宅環境をプライベートクラウド化してみましたが、ソフトウェアでインフラを制御するのはとても便利で快感です! お時間ある方は是非チャレンジしてみてはいかがでしょうか? 設計や構築方法について疑問がある方は質問していただければ可能な限りお答えしたいと思います!
kubeadmを用いたKubernetes HAクラスタ on AWS(v.1.11対応版)
前の記事を公開してすぐにv.1.11が出てしまい、構築方法が変わったので、泣きながら再検証...
構成
前提
- 作業ユーザは
root
手順
NLBの作成(AWS ManagementConsole等)
(6443/TCPのリスナを作成、aws-k8s-master[01-03]のIPをターゲットグループに登録する)
Dockerのインストール(aws-k8s-master[01-03]、aws-k8s-node[01-03])
yum install -y docker systemctl enable docker && systemctl start docker
kubeadm、kubelet、kubectlのインストール(aws-k8s-master[01-03]、aws-k8s-node[01-03])
cat <<EOF > /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=1 repo_gpgcheck=1 gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg EOF sed -i 's/^SELINUX=.*/SELINUX=permissive/g' /etc/selinux/config setenforce 0 yum install -y kubelet kubeadm kubectl systemctl enable kubelet && systemctl start kubelet
cat <<EOF > /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF sysctl --system
最初のMasterサーバの構築(aws-k8s-master01)
cat <<EOF > kubeadm-config.yaml apiVersion: kubeadm.k8s.io/v1alpha2 kind: MasterConfiguration kubernetesVersion: v1.11.0 apiServerCertSANs: - "<NLBのDNS名>" api: controlPlaneEndpoint: "<NLBのDNS名>:6443" etcd: local: extraArgs: listen-client-urls: "https://127.0.0.1:2379,https://<aws-k8s-master01のIP>:2379" advertise-client-urls: "https://<aws-k8s-master01のIP>:2379" listen-peer-urls: "https://<aws-k8s-master01のIP>:2380" initial-advertise-peer-urls: "https://<aws-k8s-master01のIP>:2380" initial-cluster: "aws-k8s-master01=https://<aws-k8s-master01のIP>:2380" serverCertSANs: - aws-k8s-master01 - <aws-k8s-master01のIP> peerCertSANs: - aws-k8s-master01 - <aws-k8s-master01のIP> networking: podSubnet: "192.168.0.0/16" EOF
kubeadm init --config kubeadm-config.yaml mkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config
SSHキーペアの作成(aws-k8s-master02, aws-k8s-master03)
ssh-keygen -t rsa -b 4096 -C ""
cat ~/.ssh/id_rsa.pub # 出力された内容をaws-k8s-master01の/root/.ssh/authorized_keysのエントリを追加する
証明書群、設定ファイル群の配布(aws-k8s-master02、aws-k8s-master03)
mkdir -p /etc/kubernetes/pki/etcd scp root@<aws-k8s-master01のIP>:/etc/kubernetes/pki/ca.crt /etc/kubernetes/pki/ca.crt scp root@<aws-k8s-master01のIP>:/etc/kubernetes/pki/ca.key /etc/kubernetes/pki/ca.key scp root@<aws-k8s-master01のIP>:/etc/kubernetes/pki/sa.key /etc/kubernetes/pki/sa.key scp root@<aws-k8s-master01のIP>:/etc/kubernetes/pki/sa.pub /etc/kubernetes/pki/sa.pub scp root@<aws-k8s-master01のIP>:/etc/kubernetes/pki/front-proxy-ca.crt /etc/kubernetes/pki/front-proxy-ca.crt scp root@<aws-k8s-master01のIP>:/etc/kubernetes/pki/front-proxy-ca.key /etc/kubernetes/pki/front-proxy-ca.key scp root@<aws-k8s-master01のIP>:/etc/kubernetes/pki/etcd/ca.crt /etc/kubernetes/pki/etcd/ca.crt scp root@<aws-k8s-master01のIP>:/etc/kubernetes/pki/etcd/ca.key /etc/kubernetes/pki/etcd/ca.key scp root@<aws-k8s-master01のIP>:/etc/kubernetes/admin.conf /etc/kubernetes/admin.conf
2台目のMasterサーバの構築(aws-k8s-master02)
cat <<EOF > kubeadm-config.yaml apiVersion: kubeadm.k8s.io/v1alpha2 kind: MasterConfiguration kubernetesVersion: v1.11.0 apiServerCertSANs: - "<NLBのDNS名>" api: controlPlaneEndpoint: "<NLBのDNS名>:6443" etcd: local: extraArgs: listen-client-urls: "https://127.0.0.1:2379,https://<aws-k8s-master02のIP>:2379" advertise-client-urls: "https://<aws-k8s-master02のIP>:2379" listen-peer-urls: "https://<aws-k8s-master02のIP>:2380" initial-advertise-peer-urls: "https://<aws-k8s-master02のIP>:2380" initial-cluster: "aws-k8s-master01=https://<aws-k8s-master01のIP>:2380,aws-k8s-master02=https://<aws-k8s-master02のIP>:2380" initial-cluster-state: existing serverCertSANs: - aws-k8s-master02 - <aws-k8s-master02のIP> peerCertSANs: - aws-k8s-master02 - <aws-k8s-master02のIP> networking: podSubnet: "192.168.0.0/16" EOF
kubeadm alpha phase certs all --config kubeadm-config.yaml kubeadm alpha phase kubelet config write-to-disk --config kubeadm-config.yaml kubeadm alpha phase kubelet write-env-file --config kubeadm-config.yaml kubeadm alpha phase kubeconfig kubelet --config kubeadm-config.yaml systemctl start kubelet
CP0_IP=<aws-k8s-master01のIP> CP0_HOSTNAME=aws-k8s-master01 CP1_IP=<aws-k8s-master02のIP> CP1_HOSTNAME=aws-k8s-master02 KUBECONFIG=/etc/kubernetes/admin.conf kubectl exec -n kube-system etcd-${CP0_HOSTNAME} -- etcdctl --ca-file /etc/kubernetes/pki/etcd/ca.crt --cert-file /etc/kubernetes/pki/etcd/peer.crt --key-file /etc/kubernetes/pki/etcd/peer.key --endpoints=https://${CP0_IP}:2379 member add ${CP1_HOSTNAME} https://${CP1_IP}:2380 kubeadm alpha phase etcd local --config kubeadm-config.yaml
kubeadm alpha phase kubeconfig all --config kubeadm-config.yaml kubeadm alpha phase controlplane all --config kubeadm-config.yaml kubeadm alpha phase mark-master --config kubeadm-config.yaml
3台目のMasterサーバの構築(aws-k8s-master03)
cat <<EOF > kubeadm-config.yaml apiVersion: kubeadm.k8s.io/v1alpha2 kind: MasterConfiguration kubernetesVersion: v1.11.0 apiServerCertSANs: - "<NLBのDNS名>" api: controlPlaneEndpoint: "<NLBのDNS名>:6443" etcd: local: extraArgs: listen-client-urls: "https://127.0.0.1:2379,https://<aws-k8s-master03のIP>:2379" advertise-client-urls: "https://<aws-k8s-master03のIP>:2379" listen-peer-urls: "https://<aws-k8s-master03のIP>:2380" initial-advertise-peer-urls: "https://<aws-k8s-master03のIP>:2380" initial-cluster: "aws-k8s-master01=https://<aws-k8s-master01のIP>:2380,aws-k8s-master02=https://<aws-k8s-master02のIP>:2380,aws-k8s-master03=https://<aws-k8s-master03のIP>:2380" initial-cluster-state: existing serverCertSANs: - aws-k8s-master03 - <aws-k8s-master03のIP> peerCertSANs: - aws-k8s-master03 - <aws-k8s-master03のIP> networking: podSubnet: "192.168.0.0/16" EOF
kubeadm alpha phase certs all --config kubeadm-config.yaml kubeadm alpha phase kubelet config write-to-disk --config kubeadm-config.yaml kubeadm alpha phase kubelet write-env-file --config kubeadm-config.yaml kubeadm alpha phase kubeconfig kubelet --config kubeadm-config.yaml systemctl start kubelet
CP0_IP=<aws-k8s-master01のIP> CP0_HOSTNAME=aws-k8s-master01 CP2_IP=<aws-k8s-master03のIP> CP2_HOSTNAME=aws-k8s-master03 KUBECONFIG=/etc/kubernetes/admin.conf kubectl exec -n kube-system etcd-${CP0_HOSTNAME} -- etcdctl --ca-file /etc/kubernetes/pki/etcd/ca.crt --cert-file /etc/kubernetes/pki/etcd/peer.crt --key-file /etc/kubernetes/pki/etcd/peer.key --endpoints=https://${CP0_IP}:2379 member add ${CP2_HOSTNAME} https://${CP2_IP}:2380 kubeadm alpha phase etcd local --config kubeadm-config.yaml
kubeadm alpha phase kubeconfig all --config kubeadm-config.yaml kubeadm alpha phase controlplane all --config kubeadm-config.yaml kubeadm alpha phase mark-master --config kubeadm-config.yaml
flannelのインストール(aws-k8s-master01)
curl -O https://raw.githubusercontent.com/coreos/flannel/v0.10.0/Documentation/kube-flannel.yml sed -i 's/10.244.0.0/192.168.0.0/g' kube-flannel.yml kubectl apply -f kube-flannel.yml
Nodeのクラスタ参加(aws-k8s-node[01-03])
kubeadm join --token <token> <NLBのDNS名>:6443 --discovery-token-ca-cert-hash sha256:<hash> # <token>、<hash>はkubeadm initをaws-k8s-master01で実行した際に表示されたものを使用
kubeadmを用いたKubernetes HAクラスタ on AWS
AWS上でkubeadm
を使い、Kubernetes HAクラスタを作ってみたときのメモです。
構成
前提
- 作業ユーザは
root
手順
Dockerのインストール(aws-k8s-master[01-03]、aws-k8s-node[01-03])
yum install -y docker systemctl enable docker && systemctl start docker
kubeadm、kubelet、kubectlのインストール(aws-k8s-master[01-03]、aws-k8s-node[01-03])
cat <<EOF > /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=1 repo_gpgcheck=1 gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg EOF sed -i 's/^SELINUX=.*/SELINUX=permissive/g' /etc/selinux/config setenforce 0 yum install -y kubelet kubeadm kubectl systemctl enable kubelet && systemctl start kubelet
cat <<EOF > /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF sysctl --system
cfssl、cfssljsonのインストール(aws-k8s-master[01-03])
curl -o /usr/local/bin/cfssl https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 curl -o /usr/local/bin/cfssljson https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 chmod +x /usr/local/bin/cfssl*
etcdサーバのためのCA証明書作成(aws-k8s-master01)
mkdir -p /etc/etcd/pki cd /etc/etcd/pki cat >ca-config.json <<EOF { "signing": { "default": { "expiry": "175200h" }, "profiles": { "server": { "expiry": "175200h", "usages": [ "signing", "key encipherment", "server auth", "client auth" ] }, "client": { "expiry": "175200h", "usages": [ "signing", "key encipherment", "client auth" ] }, "peer": { "expiry": "175200h", "usages": [ "signing", "key encipherment", "server auth", "client auth" ] } } } } EOF # 証明書の有効期限は20年
cat >ca-csr.json <<EOF { "CN": "etcd", "key": { "algo": "rsa", "size": 2048 } } EOF
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
etcdのクライアント証明書の作成(aws-k8s-master01)
cat >client.json <<EOF { "CN": "client", "key": { "algo": "ecdsa", "size": 256 } } EOF
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=client client.json | cfssljson -bare client
環境変数のエクスポート(aws-k8s-master[01-03])
export PEER_NAME=$(hostname) export PRIVATE_IP=$(ip addr show eth0 | grep -Po 'inet \K[\d.]+')
SSHキーペアの作成(aws-k8s-master02, aws-k8s-master03)
ssh-keygen -t rsa -b 4096 -C ""
cat ~/.ssh/id_rsa.pub # 出力された内容をaws-k8s-master01の/root/.ssh/authorized_keysのエントリを追加する
CA証明書とクライアント証明書の配布(aws-k8s-master02, aws-k8s-master03)
mkdir -p /etc/etcd/pki cd /etc/etcd/pki scp root@<aws-k8s-master01のIP>:/etc/etcd/pki/ca.pem . scp root@<aws-k8s-master01のIP>:/etc/etcd/pki/ca-key.pem . scp root@<aws-k8s-master01のIP>:/etc/etcd/pki/client.pem . scp root@<aws-k8s-master01のIP>:/etc/etcd/pki/client-key.pem . scp root@<aws-k8s-master01のIP>:/etc/etcd/pki/ca-config.json .
etcdサーバ証明書とpeer証明書の作成(aws-k8s-master[01-03])
cfssl print-defaults csr > config.json sed -i '0,/CN/{s/example\.net/'"$PEER_NAME"'/}' config.json sed -i 's/www\.example\.net/'"$PRIVATE_IP"'/' config.json sed -i 's/example\.net/'"$PEER_NAME"'/' config.json
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server config.json | cfssljson -bare server cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=peer config.json | cfssljson -bare peer
etcdサーバのsystemd登録と起動設定(aws-k8s-master[01-03])
export ETCD_VERSION="v3.1.12" curl -sSL https://github.com/coreos/etcd/releases/download/${ETCD_VERSION}/etcd-${ETCD_VERSION}-linux-amd64.tar.gz | tar -xzv --strip-components=1 -C /usr/local/bin/
touch /etc/etcd.env echo "PEER_NAME=${PEER_NAME}" >> /etc/etcd.env echo "PRIVATE_IP=${PRIVATE_IP}" >> /etc/etcd.env
cat >/etc/systemd/system/etcd.service <<EOF [Unit] Description=etcd Documentation=https://github.com/coreos/etcd Conflicts=etcd.service Conflicts=etcd2.service [Service] EnvironmentFile=/etc/etcd.env Type=notify Restart=always RestartSec=5s LimitNOFILE=40000 TimeoutStartSec=0 ExecStart=/usr/local/bin/etcd --name <name> --data-dir /var/lib/etcd --listen-client-urls https://<my_ip>:2379 --advertise-client-urls https://<my_ip>:2379 --listen-peer-urls https://<my_ip>:2380 --initial-advertise-peer-urls https://<my_ip>:2380 --cert-file=/etc/etcd/pki/server.pem --key-file=/etc/etcd/pki/server-key.pem --client-cert-auth --trusted-ca-file=/etc/etcd/pki/ca.pem --peer-cert-file=/etc/etcd/pki/peer.pem --peer-key-file=/etc/etcd/pki/peer-key.pem --peer-client-cert-auth --peer-trusted-ca-file=/etc/etcd/pki/ca.pem --initial-cluster aws-k8s-master01=https://<aws-k8s-master01のIP>:2380,aws-k8s-master02=https://<aws-k8s-master02のIP>:2380,aws-k8s-master03=https://<aws-k8s-master03のIP>:2380 --initial-cluster-token my-etcd-token --initial-cluster-state new # <name>にはaws-k8s-master[01-03]が入る [Install] WantedBy=multi-user.target EOF
systemctl daemon-reload systemctl enable etcd systemctl start etcd
NLBの作成(AWS ManagementConsole等)
(6443/TCPのリスナを作成、aws-k8s-master01のインスタンスをターゲットグループに登録する)
(NLB作成後、DNS名にpingを発行し、NLBのIPを確認する)
kubeadmの実行(aws-k8s-master01)
cat >config.yaml <<EOF apiVersion: kubeadm.k8s.io/v1alpha1 kind: MasterConfiguration etcd: endpoints: - https://<aws-k8s-master01のIP>:2379 - https://<aws-k8s-master02のIP>:2379 - https://<aws-k8s-master03のIP>:2379 caFile: /etc/etcd/pki/ca.pem certFile: /etc/etcd/pki/client.pem keyFile: /etc/etcd/pki/client-key.pem networking: podSubnet: 192.168.0.0/16 apiServerCertSANs: - <NLBのIP> - <my_ip> apiServerExtraArgs: apiserver-count: "3" EOF
kubeadm init --config=config.yaml
mkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config
kubeadmの実行(aws-k8s-master02,aws-k8s-master03)
mkdir /etc/kubernetes/pki scp root@<aws-k8s-master01のIP>:/etc/kubernetes/pki/* /etc/kubernetes/pki rm -f /etc/kubernetes/pki/apiserver*
cat >config.yaml <<EOF apiVersion: kubeadm.k8s.io/v1alpha1 kind: MasterConfiguration etcd: endpoints: - https://<aws-k8s-master01のIP>:2379 - https://<aws-k8s-master02のIP>:2379 - https://<aws-k8s-master03のIP>:2379 caFile: /etc/etcd/pki/ca.pem certFile: /etc/etcd/pki/client.pem keyFile: /etc/etcd/pki/client-key.pem networking: podSubnet: 192.168.0.0/16 apiServerCertSANs: - <NLBのIP> - <my_ip> apiServerExtraArgs: apiserver-count: "3" EOF
kubeadm init --config=config.yaml
mkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config
NLBへ残りのMasterを追加(AWS ManagementConsole等)
(NLBのターゲットグループにaws-k8s-master02、aws-k8s-master03を追加)
calicoのインストール(aws-k8s-master01)
kubectl apply -f https://docs.projectcalico.org/v3.1/getting-started/kubernetes/installation/hosted/rbac-kdd.yaml kubectl apply -f https://docs.projectcalico.org/v3.1/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml
Nodeのクラスタ参加(aws-k8s-node[01-03])
kubeadm join --token <token> <aws-k8s-master01のIP>:6443 --discovery-token-ca-cert-hash sha256:<hash> # <token>、<hash>はkubeadm initをaws-k8s-master01で実行した際に表示されたものを使用
kube-proxyの再設定(aws-k8s-master01)
kubectl get configmap -n kube-system kube-proxy -o yaml > kube-proxy-cm.yaml sed -i 's#server:.*#server: https://<NLBのIP>:6443#g' kube-proxy-cm.yaml kubectl apply -f kube-proxy-cm.yaml --force kubectl delete pod -n kube-system -l k8s-app=kube-proxy
kubeletの再設定(aws-k8s-node[01-03])
sed -i 's#server:.*#server: https://<NLBのIP>:6443#g' /etc/kubernetes/kubelet.conf systemctl restart kubelet
gVisorを試してみた
Googleが開発したgVisorを試して、簡単に性能調査してみましたので、メモとして残しておきます。
環境
gVisorのインストール手順
- Dockerのインストール
sudo apt-get update sudo apt-get install -y \ apt-transport-https \ ca-certificates \ curl \ software-properties-common curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - sudo add-apt-repository \ "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable" sudo apt-get update sudo apt-get install -y docker-ce
- gVisor(runsc)のインストール
wget https://storage.googleapis.com/gvisor/releases/nightly/latest/runsc chmod +x runsc sudo mv runsc /usr/local/bin sudo sh -c 'cat <<EOF > /etc/docker/daemon.json { "runtimes": { "runsc": { "path": "/usr/local/bin/runsc" } } } EOF' sudo systemctl restart docker
- コンテナを起動してみる
sudo docker run --runtime=runc hello-world sudo docker run --runtime=runsc hello-world
性能調査
簡単なスクリプトでコンテナ起動と削除のスピードを評価します。
cat <<EOF > runc-test.sh for i in \$(seq 1 \$1) ; do sudo docker run --runtime=runc --name gvisor-test hello-world > /dev/null 2>&1 sudo docker rm gvisor-test > /dev/null 2>&1 done EOF chmod +x runc-test.sh cat <<EOF > runsc-test.sh for i in \$(seq 1 \$1) ; do sudo docker run --runtime=runsc --name gvisor-test hello-world > /dev/null 2>&1 sudo docker rm gvisor-test > /dev/null 2>&1 done EOF chmod +x runsc-test.sh
スクリプトの使い方としては./runc-test.sh <起動および削除回数>
、./runsc-test.sh <起動および削除回数>
とします。試しに両方100回ずつ起動・削除を繰り返すと、以下のような結果となりました。
ubuntu@gvisor-01:~$ time ./runc-test.sh 100 real 1m20.991s user 0m14.948s sys 0m1.768s ubuntu@gvisor-01:~$ time ./runsc-test.sh 100 real 1m13.219s user 0m15.100s sys 0m1.748s
起動・停止だけではrunc
とあまり差はみられませんね。むしろrunsc
の方が速い?
ネットワークトラフィックの差をとるとrunc
に軍配が上がるみたいですが。。。
追記(2018/06/07) 気になってDisk書き込み速度も調べてみましたが、逆転現象が起きましたw
- runc
root@4aee2e622884:/# dd if=/dev/zero of=/tmp/write.tmp ibs=1M obs=1M count=1024 1024+0 records in 1024+0 records out 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 4.17698 s, 257 MB/s
- runsc
root@ce7e3926f52e:/# dd if=/dev/zero of=/tmp/write.tmp ibs=1M obs=1M count=1024 1024+0 records in 1024+0 records out 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 0.853382 s, 1.3 GB/s