- 投稿日:2019-12-19T21:58:40+09:00
k8sの運用ってどうなの?
はじめに
この記事は NTTテクノクロス Advent Calendar 2019 の22日目の記事です。
こんにちは、NTTテクノクロスでOSSクラウド基盤トータルサービスの運用を担当している土屋(@hrfm-tsu)と大野です。
その他、KubernetesやOpenStackを中心としてクラウド基盤の設計や構築を行っています。
今回は社内k8s環境を運用する際に気になったオートヒーリング後の運用について、ちょっとした知見や確認した事を共有します。
Kubernetesの特徴
まず、Kubernetes(k8s)とは
コンテナ化したアプリケーションのデプロイ、スケーリング、および管理を行うための、オープンソースのコンテナオーケストレーションシステムであり、マイクロサービスをベースとしたアプリケーションの実装方法としてよく活用されています。
今回は、いくつか存在するk8sの特徴の中で、「回復性」に着目してみたいと思います。回復性とは?
k8sの大きな特徴として宣言的設定があります。イミュータブルなインフラを作る基本的な考え方で、「システムのあるべき理想状態」を設定ファイルにて宣言することで、障害が発生してもオートヒーリング(自動復旧)してくれます。例えば、k8sでは定義ファイルはマニフェストと呼ばれ、YAML等で記述しますが、
replicas: 3と設定することでk8sクラスタ内に常に3Podを稼働させるように宣言できます。
- マニフェストの例
apiVersion: apps/v1 kind: ReplicaSet metadata: name: replicaset spec: replicas: 3 selector: matchLabels: app: replicaset-test template: metadata: labels: app: replicaset-test ver: "1.0" spec: containers: - name: pod-test image: nginx自動復旧時のPodの起動Workerはどう決まる?
k8s環境ではkube-schedulerがPodをk8s Workerにバインドする役割を担っていますが、新規Pod作成時だけではなく、オートヒーリング時の移動先k8s Workerの選定にも同様のロジック (kube-schesulerが
Worker情報が未割当のPodを検知してkube-apiserverにリクエストを送りスケジューリングする) が適用されます。
他の方のQiitaにわかりやすい記載があったので参考までに掲載します。参考
・kube-schedulerのソースコードを読みながらPodがNodeにBindされるまでを理解する
・kubernetes: スケジューラの動作障害Workerの復旧後にPodの再配置(リバランス)は行われる?
残念ながら行われません。そのため、Worker毎のPod起動数に偏りが発生します。
(k8s初心者の私はk8sでは良い感じに再配置までやってくれると期待をしていましたが。。。)それでは、再配置をしたい場合にどうすれば良いか?
- 方法1:手動でPodを削除してオートヒーリングを発動させる(強引)
- 方法2:タグ名を更新したコンテナを rollout機能で無停止での更新をする(大変)
- 方法3:Descheduler for Kubernetes機能に任せる
他にもあるかもしれませんが、今回はDeschedulerをターゲットに進めます。
Deschedulerを動かしてみる!
Deschedulerの動作概要としては
②再配置対象のPodを選定/削除
※createNodePodsMapによって削除可能なPod(再配置する対象Pod)の一覧を作る③再配備(新規作成)を既存のスケジューラ(kube-scheduler)にお願いする
では、実際に見ていきます。
事前の状態はMaster1台、Worker2台構成で、
[centos@k8s-master ~]$ kubectl get node NAME STATUS ROLES AGE VERSION k8s-master Ready master 6d23h v1.16.3 k8s-worker1 Ready <none> 6d23h v1.16.3 k8s-worker2 Ready <none> 4h3m v1.16.3 [centos@k8s-master ~]$30個のPodがWorker1,2に分散して配置されていることとします
[centos@k8s-master ~]$ kubectl get pod -o wide | grep k8s-worker1 | wc -l 14 [centos@k8s-master ~]$ kubectl get pod -o wide | grep k8s-worker2 | wc -l 16Worker02を停止してオートヒーリングを発動させてみます
[centos@k8s-worker2 ~]$ sudo shutdown -h now Connection to k8s-worker2 closed by remote host. Connection to k8s-worker2 closed. [centos@k8s-master ~]$ kubectl get node NAME STATUS ROLES AGE VERSION k8s-master Ready master 6d23h v1.16.3 k8s-worker1 Ready <none> 6d23h v1.16.3 k8s-worker2 NotReady <none> 4h8m v1.16.3 ★[centos@k8s-master ~]$ kubectl get pod -o wide | grep k8s-worker1 | wc -l 30 ★ [centos@k8s-master ~]$ kubectl get pod -o wide | grep k8s-worker2 | wc -l 16ここまでの状態で一度Deschedulerを起動してみます
[centos@k8s-master ~]$ git clone https://github.com/kubernetes-incubator/descheduler Cloning into 'descheduler'... remote: Enumerating objects: 119, done. remote: Counting objects: 100% (119/119), done. remote: Compressing objects: 100% (117/117), done. remote: Total 59287 (delta 10), reused 11 (delta 2), pack-reused 59168 Receiving objects: 100% (59287/59287), 63.61 MiB | 10.46 MiB/s, done. Resolving deltas: 100% (29113/29113), done. Checking out files: 100% (25856/25856), done. [centos@k8s-master ~]$ cd descheduler/kubernetes/ [centos@k8s-master kubernetes]$ kubectl apply -f rbac.yaml clusterrole.rbac.authorization.k8s.io/descheduler-cluster-role created serviceaccount/descheduler-sa created clusterrolebinding.rbac.authorization.k8s.io/descheduler-cluster-role-binding created [centos@k8s-master kubernetes]$ kubectl apply -f configmap.yaml configmap/descheduler-policy-configmap created [centos@k8s-master kubernetes]$ kubectl apply -f job.yaml job.batch/descheduler-job created [centos@k8s-master kubernetes]$ kubectl get job -n kube-system NAME COMPLETIONS DURATION AGE descheduler-job 1/1 27s 43s ★ [centos@k8s-master kubernetes]$ kubectl get pod -o wide | grep k8s-worker1 | wc -l 30 [centos@k8s-master kubernetes]$ kubectl get pod -o wide | grep k8s-worker2 | wc -l 16Worker02は障害中(NotReady)なので再配置されないことがわかります(想定通り)
[centos@k8s-worker3 ~]$ sudo kubeadm join 192.168.200.4:6443 --token q6wptd.z1ro8vthndp5oklc --discovery-token-ca-cert-hash sha256:aa702475624ffd50f17dbb3c98cbb2717b904e35f1b8925e68714e0d560c275e [preflight] Running pre-flight checks [WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". Please follow the guide at https://kubernetes.io/docs/setup/cri/ [WARNING SystemVerification]: this Docker version is not on the list of validated versions: 19.03.5. Latest validated version: 18.09 [WARNING Hostname]: hostname "k8s-worker3" could not be reached [WARNING Hostname]: hostname "k8s-worker3": lookup k8s-worker3 on 8.8.8.8:53: no such host [preflight] Reading configuration from the cluster... [preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml' [kubelet-start] Downloading configuration for the kubelet from the "kubelet-config-1.16" ConfigMap in the kube-system namespace [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" [kubelet-start] Activating the kubelet service [kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap... This node has joined the cluster: * Certificate signing request was sent to apiserver and a response was received. * The Kubelet was informed of the new secure connection details. Run 'kubectl get nodes' on the control-plane to see this node join the cluster. [centos@k8s-worker3 ~]$ [centos@k8s-master kubernetes]$ kubectl get node NAME STATUS ROLES AGE VERSION k8s-master Ready master 7d1h v1.16.3 k8s-worker1 Ready <none> 7d1h v1.16.3 k8s-worker2 NotReady <none> 6h14m v1.16.3 k8s-worker3 Ready <none> 40s v1.16.3 ★再度Deschedulerを実行してみます
(job名が被らないようにjob.yamlの内容を一部変更)[centos@k8s-master kubernetes]$ kubectl apply -f job.yaml job.batch/descheduler-job1 created [centos@k8s-master kubernetes]$ kubectl get job -n kube-system NAME COMPLETIONS DURATION AGE descheduler-job 1/1 27s 1h descheduler-job1 1/1 29s 43s ★今度は、状態がReadyであるWorker3に再配置されました
[centos@k8s-master kubernetes]$ kubectl get pod -o wide | grep k8s-worker1 | wc -l 16 ★ [centos@k8s-master kubernetes]$ kubectl get pod -o wide | grep k8s-worker2 | wc -l 16 [centos@k8s-master kubernetes]$ kubectl get pod -o wide | grep k8s-worker3 | wc -l 14 ★Zabbixと連携させてDeschedulerを自動起動できるか?
手動実行では面倒なので自動で実行してみたくなりました。
例えば、以下のユースケースを想定してみます。
Workerに障害が発生し、Podが起動するWorkerに偏りが発生する。
偏ったWorkerでCPU使用率が上昇する。
Zabbixが検知し再配置を実行する。実際にやってみます。
※
下記記事にもありますがCronJobにて定期的にDeschedulerをキックする方法もありますが、今回は既存監視でZabbixを使っているためこの方法で確認します参考
Kubernetesのノード障害時の挙動とノード復帰後の再スケジューリング事前の状態は先ほどと同じく
Master1台、Worker2台、30個のPodがWorker1,2に分散して配置されていることとします[centos@k8s-master ~]$ kubectl get node -o wide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME k8s-master Ready master 7d19h v1.16.3 192.168.200.4 <none> CentOS Linux 7 (Core) 3.10.0-693.17.1.el7.x86_64 docker://19.3.5 k8s-worker1 Ready <none> 7d19h v1.16.3 192.168.200.5 <none> CentOS Linux 7 (Core) 3.10.0-693.17.1.el7.x86_64 docker://19.3.5 k8s-worker2 Ready <none> 23h v1.16.3 192.168.200.6 <none> CentOS Linux 7 (Core) 3.10.0-693.17.1.el7.x86_64 docker://19.3.5 [centos@k8s-master ~]$ [centos@k8s-master ~]$ kubectl get pod -o wide | grep k8s-worker1 | wc -l 16 [centos@k8s-master ~]$ kubectl get pod -o wide | grep k8s-worker2 | wc -l 14 [centos@k8s-master ~]$ kubectl get job -n kube-system -o wide No resources found in kube-system namespace.Worker02で障害(サーバ停止)を発生させる
[centos@k8s-worker2 ~]$ sudo shutdown -h now Connection to k8s-worker2 closed by remote host. Connection to k8s-worker2 closed. [centos@k8s-master ~]$ kubectl get node -o wide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME k8s-master Ready master 7d19h v1.16.3 192.168.200.4 <none> CentOS Linux 7 (Core) 3.10.0-693.17.1.el7.x86_64 docker://19.3.5 k8s-worker1 Ready <none> 7d19h v1.16.3 192.168.200.5 <none> CentOS Linux 7 (Core) 3.10.0-693.17.1.el7.x86_64 docker://19.3.5 k8s-worker2 NotReady <none> 23h v1.16.3 192.168.200.6 <none> CentOS Linux 7 (Core) 3.10.0-693.17.1.el7.x86_64 docker://19.3.5 [centos@k8s-master ~]$ kubectl get pod -o wide | grep k8s-worker1 |wc -l 30 ★ [centos@k8s-master ~]$ kubectl get pod -o wide | grep k8s-worker2 |wc -l 14その後、Worker03を追加する(手順省略)
Worker02の障害によりWorker01にPodが移動したため
Worker01のCPU使用率が増加する
(今回は試験簡略化のため以下コマンドを実行)[centos@k8s-worker1 ~]$ stress --cpu 4 --timeout 2m stress: info: [24413] dispatching hogs: 4 cpu, 0 io, 0 vm, 0 hdd stress: info: [24413] successful run completed in 120sCPU使用率の上昇を検知し、ZabbixからDeschedulerが自動で実行している
[centos@k8s-master ~]$ kubectl get job -n kube-system NAME COMPLETIONS DURATION AGE descheduler-job1 1/1 27s 43s ★正しくDeschedulerが動きPodの再配置が行われている
[centos@k8s-master ~]$ kubectl get pod -o wide | grep k8s-worker1 | wc -l 16 ★ [centos@k8s-master ~]$ kubectl get pod -o wide | grep k8s-worker2 | wc -l 14 [centos@k8s-master ~]$ kubectl get pod -o wide | grep k8s-worker3 | wc -l 14 ★感想
単に機能を動かしてみるレベルでは簡単ですが、
実際に障害を想定した運用を行うために(例えば)以下のような知識や設計が必要になってきます。
- kube-schedulerのフィルタや優先度付けの仕組みと設定内容を理解すること
- Deschedulerを実行する条件/前提を明確にすること
- 例えば、CPU負荷だけの条件ならばPodをautoscalingさせることも一つの手段か?
- 障害時にどこまで自動復旧するか。自動復旧の範囲を明確にすること
- 例えば、Cluster Autoscaler機能を使い、リソースが枯渇して既存のWorkerにpodがschedulingできない場合にWorker追加まで自動復旧させる?
様々なk8sの機能やエコシステムの理解(キャッチアップ)だけでも大変ですが、要件に沿った組み合わせ(設計)はより大変だと感じました。
おわりに
今回は、k8s初心者が社内k8s基盤の運用を考えた時に、気になった事の一つであるPod障害時の運用方法について簡単に紹介してみました。
今後もk8sに関連した投稿をしていきたいと思います。明日は、@yuitomoさんのディープラーニング関連の記事です。
お楽しみに~!
- 投稿日:2019-12-19T21:50:08+09:00
Windows 10 proにDocker環境を構築する
全体の手順
- PCスペックの確認
- Hyper-Vの有効化
- installerの取得
- インストール
PCスペックの確認
- [Windows] - [設定] - [システム] -[バージョン情報]
- 以下の条件を満たしていることを確認
- システムの種類:64ビット
- エディション: Windows10 Pro
Hyper-Vの有効化
- [コントロールパネル]-[プログラム]-[windowsの機能の有効かまたは無効化]
- Hyper-Vを有効にする
- PCを再起動する
Docker for windows をインストールする
installerをゲットするにははDocker Hubにログインが必要。
IDはpublicリポジトリ名と合わせて表示されるので慎重に考えましょう。アカウントを作成してsign inすると
Docker for windowsのインストール案内がでました。設定は全てdefaultで進めて、install完了後に再起動。
再起動後にPowerShellを起動し、以下のコマンドを実行docker --versionversionが表示されればinstall OKです
次回
- Dockerの起動
- コンテナの作成
参考リンク
- 投稿日:2019-12-19T20:23:56+09:00
とりあえずつかってみようぜDockerを
はじめに
いなたつアドカレの十九日目の記事です。
もうあと1週間を切りましたね。。。
ネタも切れてますが。。。。
先日Dockerの簡単な導入をハンズオンで開催したので、その資料を供養しようかと、、、
雰囲気ですら理解せずに使ってみる
コンテナとか仮想でうんたらとかとりあえずおいといて使ってみようよの会ですね。
dockerの愉快なコマンドたち
- docker run
- コンテナを引っ張ってきて起動するコマンド
- docker exec
- コンテナ内でコマンドを実行するコマンド
- docker ps
- コンテナの起動状況を確認するコマンド
- docker stop
- コンテナを止めるコマンド(ころころする)
- docker rm
- コンテナを削除するコマンド(成仏してクレメンス)
- docker start
- コンテナを蘇生するコマンド(ザオリク?ドラクエしらねぇ)
$ docker stop [CONTAINER_NAME]でコンテナさんの命を断ちます、しかし、この世界は蘇生ができる世界なので成仏するまでは復活する可能性があります。
しかし$ docker rm [CONTAINER_NAME]でお亡くなりになっているコンテナさんに成仏していただくことができます。
そして、お亡くなりになっているコンテナに$ docker start [CONTAINER_NAME]をすることで、蘇生できます。docker run のオプション
- iオプション -i
- ホスト -> コンテナ の入出力をつなげる
- tオプション -t
- コンテナ -> ホスト の入出力をつなげる
- dオプション -d
- バックグラウンド実行
- vオプション -v
- ファイルを共有する
- pオプション -p
- ポートをつなげる
- wオプション -w
- 作業ディレクトリを指定する
- nameオプション --name
- コンテナに名前をつける
- rmオプション --rm
- コンテナをstopしたら自動でrmする
オプションitdはハッピーセット
docker run の実際の例
$ docker run -itd --name python -v $(PWD):/py -p 8000:8000 -w="/py" python $ docker run -itd --name [CONTAINER NAME] -v $(PWD):[CONTAINER DIRCTORY] -p [LOCAL PORT]:[CONTAINER PORT] -w="[CONTAINER DIRCTORY]" [IMAGE NAME]$(PWD) はローカルのカレントディレクトリを展開(pwdコマンドの実行)
docker-compose
docker-compose.ymlにコンテナの概要を記述し、Dockerファイルを用いてコンテナの詳細を定義する。
とりあえず触ってみようかこまんど
- docker-compose run CONTAINER_NAME COMMAND
- 指定したコンテナでコマンドを実行する (up より前に)
- docker-compose up
- コンテナを全て起動する、ログ一生吐き続けるので -d をつけよう
- docker-compose exec CONTAINER_NAME COMMAND
- 指定したコンテナでコマンドを実行する (up より後に)
- docker-compose down
- docker-composeで管理している全てのコンテナに対してstopとrmをする
- docker-compose ps
- コンテナの状態の確認
- docker-compose logs CONTAINER_NAME
- 指定コンテナのログをみる
つかう
- docker-compose up -d
- docker-compose ps
- docker-compose exec nginx bash
- docker-compose down
おまけ
便利なやつ
- docker stop \$(docker ps -a -q) && docker rm \$(docker ps -a -q)
- 全てのコンテナを亡きものにする、ころころして成仏していただく
- 投稿日:2019-12-19T19:53:55+09:00
DockerでUbuntu18.04+Pythonの機械学習用の環境を1時間で用意するチャレンジをしてみた
はじめに
この記事はとりあえずなんでも Advent Calendar 2019の21日目の記事です。
とある日に思った
Windows環境にPythonとpyTorchを入れて適当に機械学習を回していたのですが、突然
「あー、自由にいじれるLinuxがほしい。でもVMはなんかかっこ悪いし、重たいしやだ(偏見)」
「DockerでUbuntu入れてみるとDockerの勉強になったりするのでは?」
「なんかモダンな環境構築っぽい(知識少なすぎて他の構築方法VMくらいしか知らない)」
「1時間あるし、構築チャレンジするか!!」
と、完全に思いつきだけで構築チャレンジをしてみました。
なので、Win10にDockerを使ってUbuntu環境を作る、です。
その時のメモを公開します。自分のスペック
・VM構築経験なし(なのに偏見持ち)
・Linux初心者(実は初めてのLinux環境構築)
・Docker初心者(1回触ったくらい)という初心者丸出しのスペックなので、相当躓きました。
躓いた箇所を全部メモしておいたので、温かい目で見てください。1時間もかかるの?
そんなことありません。ある程度知っている方がやれば1時間どころか15分くらいで終わると思います。
躓いて、調べて、PC再起動して、野暮用で時間を消費して、間にこのメモを書きつつ実行してを全て含めて、1時間です。
(記事にするにあたって色々MarkDownで囲っただけなので、コマンドのメモとかも全部その1時間内に書いています)
タイマーを使って何度か時間を確認していたので、時間軸でお楽しみください。それでは構築スタート。
https://www.docker.com/get-started
からDocker Desktopを入手
サインインが必要
適当にサインアップしてゲット~2分~
installer起動して、すべてデフォルトでポチポチ
その間にUbuntuを起動する方法を調べておく
https://weblabo.oscasierra.net/docker-ubuntu1604/docker pull ubuntu:16.04 docker run -it -d --name ubuntu1604 ubuntu:16.04でOKっぽいが、18.04を使うか
install完了にサインアウトが必要らしく、投げ出される~5分~
PC起動待ち
~7分~
Hyper-V無効化されていると言われる
有効化したいので再起動
なんか更新プログラムも走って2回再起動した
野暮用もあり時間を消費する~24分~
コマンドプロンプトから
docker pull ubuntu:18.04を打ち込む
Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting for conne ction (Client.Timeout exceeded while awaiting headers)dockerのsettingsからプロキシ設定する
リトライしてok~27分~
docker run -it -d --name ubuntu1804 ubuntu:18.04 docker exec -it ubuntu1604 /bin/bashbashが起動できた!
~28分~
pythonが入っていないので入れることにした
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-linux-python.html$ apt-get install python3E: Unable to locate package python3https://qiita.com/hatorijobs/items/c503840c13672e12d188
え、vimも入っていないの…$apt updateConnection refusedする。IPは91.189.88.24 の80番ポート
$ping 91.189.88.24 ping: command not foundえ、pingも入っていないの…!?
まぁつながらないのは99%くらいプロキシだろうからいいか。$export HTTP_PROXY=[使っているプロキシ] $export HTTPS_PROXY=[使っているプロキシ]これでも駄目。
https://qiita.com/48saaan/items/47f8d9cd3321c3bcfce6
aptは小文字らしい。Case Sensitiveなの知らなかった。$export http_proxy=[使っているプロキシ] $export https_proxy=[使っているプロキシ]$apt updateいけた。
~40分~
$apt install vim $apt install python3.8いけたいけた。
ここでお菓子を取りに行って時間を消費。~48分~
pipを入れようと思う
$curl https://bootstrap.pypa.io/get-pip.py -o get-pip.pycurlないの!?
$apt install curl $curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py★ちなみにcurlは大文字のHTTP_PROXYを参照する…
$python3.8 get-pip.py ModuleNotFoundError: No module named 'distutils.util'https://www.bioerrorlog.work/entry/install-pip-pip3-ubuntu
pip3はget-pip.pyから入れられないのか…$apt install python3-pip入った。
試しにnumpyとか入れてみるか。$pip3 install numpy★16.04の版ではここでエラー。python2系と3系が同居してしまっていた。
ImportError: cannot import name main
https://qiita.com/Suzukaze31/items/e6d15ddd9ffcd5e6c246
二つ目の対処をやればOKだった。めでたくUbuntu+python環境完成!!!
~57分~
調子に乗ってtorch入れる
$pip install torch確認する。
$python3 >>>import torch >>>x=torch.ones(2,2) >>>print(x) >>>exit(0)2x2の単位行列が作れたことを確認したのでOK。
ここで60分。終わりに
今の時代こんなに簡単に環境構築できるとは。そして自分のスキルのなさを痛感しました。
dockerfile書けとか言われてもまだ書けないので、今度書いてみます。
なんにせよ、好きにいじれるLinux環境をゲットできたので、色々やってLinux勉強しようと思います。
- 投稿日:2019-12-19T17:44:35+09:00
Rails, Dockerのマルチステージビルドに失敗した時の対応
問題
- dockerのマルチステージビルドにて
bundle installの内容をコピーしていた
COPY --from=builder /usr/local/bundle /usr/local/bundle- ここについての詳細は、Railsのdockerイメージを小さくする方法などで調べてください
Bundler 2.1.1,RubyGem 3.1.1がリリースされたことで、dockerビルド時のバージョンが勝手にアップデートされ、Railsが起動できなくなった対応
/usr/local/libもコピーするCOPY --from=builder /usr/local/lib /usr/local/lib COPY --from=builder /usr/local/bundle /usr/local/bundle詳細
エラーの詳細
- nokogiriなどの
with native extensionなgemが全て読み込まれなくなっていた
- 以下のようなエラーが発生
- bundle実行時
Could not find nokogiri-1.10.7 in any of the sourcesgem listなど実行時
Ignoring nokogiri-1.10.7 because its extensions are not built. Try: gem pristine nokogiri --version 1.10.7対応について
/usr/local/libをコピーしたものとしていないものを比較すると、/usr/local/lib/ruby/site_rubyの容量が変わっていたため、このあたりにnative extension周りのものが含まれると思われる(ここの詳細はわかっていません)
/usr/local/libではなく、/usr/local/lib/rubyのみのコピーでも動作可能/usr/local/lib/ruby配下はsite_ruby以外に容量の変化はなかったため、/usr/local/lib/ruby/site_rubyまで指定する必要はないように思われる
- 投稿日:2019-12-19T15:29:02+09:00
sbtを使ってDockerize
dockerizeに便利なプラグインを追加
sbt-native-packager:https://github.com/sbt/sbt-native-packager
plugins.sbtaddSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.5.1")プラグインを有効化
build.sbtenablePlugins(JavaAppPackaging)Dockerfile自動生成
# Dockerfileを自動生成 $ sbt docker:stage target/docker/stage/opt/Dockerfileが作成されるおまけ
# Dockerイメージを生成 $ sbt docker:publishLocal
- 投稿日:2019-12-19T15:28:29+09:00
DockerとDocker ComposeをUbuntu18.04にインストールする。2019年冬
概要
2019年12月にUbuntu18.04にDockerをインストールする手順についてまとめます。
なるべく新しいのを入れます。環境
% cat /etc/lsb-release DISTRIB_ID=Ubuntu DISTRIB_RELEASE=18.04 DISTRIB_CODENAME=bionic DISTRIB_DESCRIPTION="Ubuntu 18.04.3 LTS"とりあえず何もしないでaptで入れられるやつ
% sudo apt update % sudo apt install docker docker-compose% docker -v Docker version 18.09.7, build 2d0083d % docker-compose -v docker-compose version 1.17.1, build unknownなるべく新しいのを入れる
これらの方がが新しいみたいなのでこちらを使います。
「とりあえず何もしないでaptで入れられるやつ」でインストールしましたがそれらはなかったことにして、Docker系は何もインストールしていない状態からの手順を書きますGet Docker Engine - Community for Ubuntu
https://docs.docker.com/install/linux/docker-ce/ubuntu/
詳細は上記URLの公式ドキュメントを参照してください。
実行したコマンドだけ書きます。% sudo apt update % sudo apt-get install \ apt-transport-https \ ca-certificates \ curl \ gnupg-agent \ 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 update % sudo apt install docker-ce docker-ce-cli containerd.io % docker -v Docker version 19.03.5, build 633a0ea838
docker: Got permission deniedと出る場合は以下のコマンドを実行する。% sudo usermod -aG docker ${USER}上記コマンドを実行した後、一度exitしてからログインしなおせばエラーが出なくなる。
Install Docker Compose
https://docs.docker.com/compose/install/
詳細は上記URLの公式ドキュメントを参照してください。
実行したコマンドだけ書きます。
上述の通りDockerのインストールは済んだ状態で進めます。% sudo curl -L "https://github.com/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose % sudo chmod +x /usr/local/bin/docker-compose % docker-compose -v docker-compose version 1.25.0, build 0a186604
/usr/binにlnを作っておくと親切だと思うけど必須ではない。% sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-composeまとめ
https://docs.docker.com/ の手順に従い、新しいDockerがUbuntu18.04にインストールできました
- 投稿日:2019-12-19T15:03:18+09:00
GitLab CI/CDによるDocker環境へのパイプライン考察
この記事は富士通システムズウェブテクノロジー Advent Calendarの20日目の記事です。
本記事の掲載内容は私自身の見解であり、所属する組織を代表するものではありません。はじめに
GitLab CI/CD 便利ですよね。Gitリポジトリへのコミット等をトリガーに自動処理を実行できます。
自由度が高いので何でもできるのですが、逆に自由すぎて迷うことも多々あります。
本記事では、Docker環境を活用したCI/CDの型について模索してみたいと思います。この延長で、社員が気軽にアイデアを試せる下記のような環境を作ることを目指しています。
- Webサービスを動かすマシンを自分で用意しなくていい
- サーバOSにログインしてインストール・セットアップ作業をしなくていい
- GitリポジトリにコードをコミットするだけでWebサービスが動く
※ちなみに筆者はKubernetesについては実践経験がありません。スモールスタート主義なので、Dockerだけだと無理だ・・・と実感してから検討したい派。実はまだDocker Composeも使っていません。が、Docker Composeはさすがに使いたくなってきたところ・・・。
環境
本記事の試行錯誤の環境は下記のとおりです。
- GitLab環境
- GitLab.com
- ビルドサーバ (CPU: 2core, MEM: 4GB)
- CentOS 7.7
- Docker CE 19.03.5
- GitLab Runner 12.5.0
- デプロイ先サーバ (CPU: 2core, MEM: 4GB)
- CentOS 7.7
- Docker CE 19.03.5
※実際には社内ネットワークからのインターネットアクセスには認証プロキシを突破するための設定が必要ですが、本記事では本質ではないため割愛しています。
CI/CDパイプラインの設計
Dockerのポータビリティを活かしたい、言い換えると、OSに直接何かをインストールすることを極力避けたいです。
- Webサービスの構成要素はすべてDockerコンテナにする
- アプリケーションのビルド環境にもDockerコンテナを使う
この路線でCI/CDパイプラインを設計すると下記のようになります。
- ビルド用コンテナをビルドする
- ↑のビルド用コンテナを使ってアプリケーションをビルドし、Webサービスコンテナにする
- Webサービスコンテナを別サーバであるデプロイ先サーバ上に起動する
0.ビルド用コンテナをビルドする準備
まずはビルドサーバを構築します。
CentOSにDockerをインストールする手順はDocker本家に詳しく書かれているので割愛します。
また、GitLab Runnerをインストールする手順についてもGitLab本家をご参照ください。ここではDockerコンテナを使って自動ビルドできるようにしたいため、Docker ExecutorモードでGitLab Runnerをregisterします。(やはり本家の手順書が参考になります。)
ただ、ちょっと待てよ。ビルド用コンテナをビルドするためのコンテナは何にすればいいのか?
そもそも、Dockerコンテナの中でDockerイメージをビルドできるのか?など疑問が次々と出てきます。それで色々と勉強したのですが、主に下記記事はたいへん参考にさせていただきました。
まとめると、Dockerコンテナの中でDockerイメージをビルドする方法は下記の通り:
- Docker in Docker、Docker outside of Docker、Daemon-less Image Builder の3方式がある
- Docker in Docker(DinD)は権限が強すぎて危なそう
- Daemon-less Image Builderはまだあんまり事例がない
- CIで使う時はDocker outside of Docker(DooD)でいいんじゃないか?という情報が多い
ということで素直にDocker outside of Docker(DooD)方式を採用することにします。
Docker outside of Docker(DooD)をするには具体的に何をすればいいのでしょうか?
どうやらDocker Hubにdockerという名前のコンテナがあるらしく、このコンテナはDockerの中でDockerを使うためのコンテナのようです(DinD、DooD兼用)。素晴らしい!(素晴らしいが名前が極めて紛らわしい!)
このdockerコンテナを使った上で、「コンテナ側からホストのdocker.sock (/var/run/docker.sock)をマウント」すればいいらしいです。(この仕組みについては、まだ人様に説明できるほど理解できていません。)GitLab Runnerのregisterは下記の手順で実施しました
# gitlab-runner register -n \ --url <GitLab URL> \ --registration-token <token> \ --executor docker \ --description <サーバ名等> \ --tag-list "docker-build" \ --docker-image "docker:latest" \ --docker-volumes /var/run/docker.sock:/var/run/docker.sock
- 4行目
--executor dockerはDocker Executorとしてregisterするという意味- 6行目
--tag-list "docker-build"はdocker-buildというタグ名で登録という意味- 7行目
--docker-image "docker:latest"がDockerの中でDockerを使うためのコンテナを指定- 8行目
--docker-volumes /var/run/docker.sock:/var/run/docker.sockがコンテナ側からホストのdocker.sockマウント1.ビルド用コンテナをビルドする
Docker outside of Docker(DooD)の環境ができたので、早速ビルド用のコンテナを作ってみることにします。
言語は何でもいいのですが、私が一番馴染みがあるJavaをGradleでビルドするコンテナを作ります。GitLabに新規プロジェクトを作成します。ここでは名前を「gradle-container」とします。
このプロジェクトには下記2ファイルを配置してコミットします。DockerfileFROM gradle:6.0.1-jdk13.gitlab-ci.ymlstages: - package package: stage: package tags: - docker-build script: - docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY} - docker build -t ${CI_REGISTRY_IMAGE} . - docker push ${CI_REGISTRY_IMAGE}
tagsに指定しているdocker-buildは、register時に指定したタグ名これらのファイルをコミットすると自動ビルドが実行され、見事ビルド用コンテナができあがります。
※この例は、Docker Hubに置いてあるgradleコンテナを持ってきて、そのままGitLab Registryに格納しているだけですが、ビルド環境にカスタマイズを入れたい場合にこのDockerfileを修正するだけなのでCI/CDの型としては重宝します。2.ビルド用コンテナを使ってアプリケーションをビルドし、Webサービスコンテナにする
上記で作成したビルド用コンテナを使って、次にアプリケーションをビルドします。
GitLabに新規プロジェクトを作成します。ここでは名前を「sampleapp」とします。
自動ビルドを制御する下記2ファイルを作成してコミットします。
(アプリケーションのソースコードは割愛します。素のServlet/JSPを想定。)gitlab-ci.ymlstages: - build build: stage: build image: <ビルド用コンテナのURL>:latest tags: - docker-build script: - gradle war artifacts: paths: - build/libs/*.warbuild.gradleapply plugin: 'eclipse-wtp' apply plugin: 'war' repositories { jcenter() } dependencies { providedCompile 'javax.servlet:javax.servlet-api:3.1.0' } sourceCompatibility = '1.8' targetCompatibility = '1.8'
buildジョブのimageにビルド用コンテナを指定していますこれで、自分で作ったビルド用コンテナを使ってアプリケーションのビルドに成功しました。
続いて、このアプリケーションをWebサービスコンテナにしましょう。同じGitLabプロジェクトに下記を追加します。
gitlab-ci.ymlstages: - build - package build: <省略(上記参照)> package: stage: package tags: - docker-build script: - docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY} - docker build -t ${CI_REGISTRY_IMAGE} . - docker push ${CI_REGISTRY_IMAGE} dependencies: - buildDockerfileFROM tomcat COPY build/libs/*.war /usr/local/tomcat/webapps/
- アプリケーションをWebサービスとして動かすためにTomcatを使います。Dockerfileでは
tomcatコンテナをベースに、ひとつ前のジョブで作成したアプリケーションのWARファイルを同梱しています。自分で作ったビルド用コンテナを使ってアプリケーションをビルドし、それをWebサービスコンテナにすることに成功しました。
3.Webサービスコンテナを別サーバであるデプロイ先サーバ上に起動する
最後に上記で作成したWebサービスコンテナをデプロイします。
さて、GitLab CI/CDを使ってデプロイ先サーバ上でWebサービスコンテナを起動するにはどうすればいいでしょうか?
デプロイ先サーバにGitLab Runnerを入れてしまうことを考えましたが、アプリケーションの実行環境にはあまり入れたくありません。
軽く調べた結果、GitLab RunnerにSSH Executorというモードがあります。これを使えば、ビルドサーバ上から別サーバを操作できそうです。接続のための情報もビルドサーバに保存されるので、GitLab上にパスワードを設定するよりは安全なのではないかと。GitLab Runner SSH Executorのregister手順は割愛しますが、対話型で接続先のサーバのIPアドレス、ユーザ、パスワードまたは鍵ファイルを指定するだけです。タグ名は
docker-sshにしたと仮定します。さて、実際にデプロイを行うスクリプトを書いていきましょう。
※デプロイと言っても、ここでは簡単にdocker runで起動する程度に留めます。GitLabプロジェクトを新規作成します。ここではプロジェクト名は「sampleapp-deploy」とします。
.gitlab-ci.ymlstages: - deploy deploy_review_app: tags: - docker-ssh stage: deploy variables: GIT_STRATEGY: none script: - sudo docker login -u gitlab-ci-token -p ${CI_BUILD_TOKEN} ${CI_REGISTRY} - sudo docker pull <sampleappコンテナのURL>:latest - sudo docker rm -f sampleapp - sudo docker run --name sampleapp -d -p 8080:8080 <sampleappコンテナのURL>:latest environment: name: review url: http://xxx.xxx.xxx.xxx:8080/ on_stop: stop_review_app when: manual stop_review_app: tags: - docker-ssh stage: deploy variables: GIT_STRATEGY: none script: - sudo docker stop sampleapp when: manual environment: name: review action: stop environment: name: review action: stop
- デプロイと停止はマニュアルジョブとして定義しました。
- GitLab CI/CDのEnvironment機能を活用して、デプロイと停止が対になるように設定しています。
- デプロイした際に、GitLabのUIからアプリの画面を直接起動できるURLを設定しています。
- ※初回実行に失敗するバグがあります(これがDocker Composeを使いたい理由の第一位)
パイプライン考察
GitLab CI/CDによるDocker環境へのパイプラインの型をまとめると下図の通りです。
- ソースコードをビルドしてコンテナにするまでをビルドプロジェクト(CI)、デプロイ先サーバにデプロイするのはデプロイプロジェクト(CD)と、プロジェクト分割している。実際は複数モジュールを組み合わせてデプロイすることや、複数環境にデプロイすることなどを考慮しなければならない。その時の柔軟性を考慮すると、この分割の仕方が良いと思っている。
- 上記を実現するためには、ビルドプロジェクトの成果物には環境依存の情報を含めてはいけない。Dockerコンテナ起動時に環境変数として渡すか、マウント先のファイルで制御できるようにする。
- SSH Executorがベストソリューションなのか自信がない。Docker Executor上でAnsibleによる制御の方が良い気もしているが、その場合、サーバへの接続情報はGitLabのSECRET VARIABLES等を使うのだろうか?
- 今後の検討事項
- Webサービスを複数コンテナ構成にする(アプリケーションとデータベース等)
- 検証環境と本番環境といった複数デプロイ環境に対応する。いや、ブランチごとに別環境としてデプロイする場合にはどうすればいいか?
- デプロイパイプラインを特定の人しか実行できないようにするにはどうすればいいか?
- 監視、ログなどを共通的に実現できないか?
- 環境を汚さないのはいいけど遅い!
こんな感じでやりたいことを消化していくと、いつかKubernetesが欲しいと思うようになる日が来るのだろうか?
おわりに
この半年間、少しずつ時間をかけてGitLab CI/CDとDockerを実際に使ってみて、環境を汚さないって素晴らしい!すべてをコードで記述するって素晴らしい!と感動しています。
これから、実際のプロジェクトでこういった技術を使う機会が増えてくればいいなぁ。
- 投稿日:2019-12-19T14:58:22+09:00
Docker上で mysqlコンテナにログインする方法
Docker上でMySQLにログインするには、docker composeのコマンドと一緒にmysqlのログインコマンドを入力する必要があります。
Docker上では以下のコマンドでMySQLにログインできます。
$ docker exec -it [コンテナ名] mysql -u root -pでは、確認していきます。
まず、docker-compose psコマンドで、MySQLのコンテナが起動していることを確認します。$ docker-compose ps 指定されたパスが見つかりません。 Name Command State Ports --------------------------------------------------------------------------------------- composer /bin/sh /docker-entrypoint ... Exit 0 laravel docker-php-entrypoint /usr ... Exit 0 mysql docker-entrypoint.sh mysql ... Up 0.0.0.0:33306->3306/tcp, 33060/tcp nginx nginx -g daemon off; Up 0.0.0.0:8080->80/tcp php-fpm docker-php-entrypoint php-fpm Up 9000/tcpコンテナ名(Name)が
mysqlになっているコンテナが起動中のmysqlコンテナです。さっそく、ログインしてみます。
ターミナル$ docker exec -it mysql mysql -u root -p Enter password:ログイン成功後に、生成されているデータベースを一覧表示できていることがわかります。
実行結果Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 9 ~(省略)~ Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>show datases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | +--------------------+ 5 rows in set (0.01 sec)以上です。
Docker勉強中で分からないことが多いので、積極的に勉強中です!
- 投稿日:2019-12-19T13:04:57+09:00
SpringBoot1.5 + Gradle4.4 + Java8 + Docker 環境を Java11 に対応させる
この記事は、Java Advent Calendar 2019 15日目の記事です。
はじめに
Java8の無償サポートが2019年1月に切れてから一年ほど放置してましたが、
今回時間ができたので8以降初のLTSであるJava11への更新を行いました
その時のメモですと書き始めようとしましたが、OpenJDK8は2023年6月までサポートされるらしいので、
OracleJDKからOpenJDKに変えるだけでよかったのでは......
でもやってしまったので記録しときますJDKのアップデート
AdoptOpenJDK11をインストール
以下のコマンドを入れると最新のJDKがインストールされる
brew cask install adoptopenjdkしかし、現状ではJDK13が入ってしまうので、LTS版であるJDK11を入れるにはバージョンを指定する必要がある
ということで公開されているバージョンを検索$ brew search adoptopenjdk ==> Casks adoptopenjdk adoptopenjdk11-openj9-jre adoptopenjdk12-openj9 adoptopenjdk13-jre adoptopenjdk8 adoptopenjdk8-openj9-large adoptopenjdk10 adoptopenjdk11-openj9-jre-large adoptopenjdk12-openj9-jre adoptopenjdk13-openj9 adoptopenjdk8-jre adoptopenjdk9 adoptopenjdk11 adoptopenjdk11-openj9-large adoptopenjdk12-openj9-jre-large adoptopenjdk13-openj9-jre adoptopenjdk8-openj9 adoptopenjdk11-jre adoptopenjdk12 adoptopenjdk12-openj9-large adoptopenjdk13-openj9-jre-large adoptopenjdk8-openj9-jre adoptopenjdk11-openj9 adoptopenjdk12-jre adoptopenjdk13 adoptopenjdk13-openj9-large adoptopenjdk8-openj9-jre-large今回入れたいのはJDK11なので、以下のコマンドでバージョンを指定してインストール
brew cask install adoptopenjdk11すでに通っているPATHをJDK11に変更
export JAVA_HOME=`/usr/libexec/java_home -v 11`バージョンを確認
$ java -version openjdk version "11.0.5" 2019-10-15 OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.5+10) OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.5+10, mixed mode)IntelliJのProjectSDKにJDK11を指定
Command + ; でProjectStructureを開き、ProjectSDKとProjectLunguageLebelにJDK11を指定
Gradleをアップデート
Gradle4.4はJDK11に対応していないため、アップデートする必要がある
5.0以降のバージョンは対応しているようだが、折角なので現在の最新である6.0.1にしてみるgradle-wrapper.propertiesの更新
gradle/wrapper/gradle-wrapper.properties に記載されているバージョンを更新すればプロジェクトに適用されるGradleのバージョンが変更される
今回は以下の 4.4 の部分を 6.0.1 に変更するだけdistributionUrl=https\://services.gradle.org/distributions/gradle-4.4-bin.zipgradlewを更新
それだけだとgradlewに変更が伝播しないので、gradlewを生成し直す
./gradlew wrappergradle.buildを更新
各種フレームワーク・ライブラリをJDK11に対応したものに変更していく
基本的には全てgradle.buildに記載されているので、それを修正していけばよいJavaのバージョン指定を変更
各指定の意味は公式に記載されているので、必要な物を指定する
sourceCompatibility = 11 targetCompatibility = 11Gradle6系の記載方法に変更
jarの指定方法が変更になっているので更新
詳細は公式を参照のことjar { baseName = 'example' version = '1.0.0-SNAPSHOT' }上記だったものを以下に変更
bootJar { archiveBaseName = "example" archiveVersion = "1.0.0-SNAPSHOT" }SpiringBootのバージョンを変更
Java11を利用するにはSpringBoot2.1.x以上が必要
折角なので現在の最新である2.2.2にしてみる
基本的には公式のマイグレーションガイドに従えばいいbuildscript { ext { springBootVersion = '1.5.13.RELEASE' } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } }SpringBootが自動で依存関係管理プラグインを適用しなくなったので、プラグインも追加する
apply plugin: 'io.spring.dependency-management'メインクラスの指定方法が変わっているので、それも変更
springBoot { mainClassName = "jp.co.example.Application" }ライブラリのバージョンを更新
MavenRepositoryを見ながらライブラリのバージョンを更新していく
SpringBoot周りのライブラリ
SpringBoot周りのライブラリはバージョンを変数で指定しておくと楽
ただし、一部SpringBootのバージョンと異なる場合があるので注意が必要dependencies { compile("org.springframework.boot:spring-boot-starter-web:${springBootVersion}") compile("org.springframework.boot:spring-boot-starter-jdbc:${springBootVersion}") compile("org.springframework.boot:spring-boot-starter-security:${springBootVersion}") compile("org.springframework.boot:spring-boot-starter-actuator:${springBootVersion}") testCompile("org.springframework.boot:spring-boot-starter-test:${springBootVersion}") testCompile("org.springframework.security:spring-security-test:5.2.1.RELEASE") }lombok
依存関係の指定方法が変わっているため、普通にバージョンだけ指定して更新するとビルド時にlombokで自動生成されるメソッドが見つからないとエラーが出る
公式を参考にして、以下の指定を追加するcompileOnly('org.projectlombok:lombok:1.18.10') annotationProcessor('org.projectlombok:lombok:1.18.10')また、@Valueを使っていると、Jacksonでのデシリアライズがうまく機能しないエラーが発生する
project直下に lombok.config というファイルを作って以下を記載することで回避できる
その他の設定については公式のマイグレーションガイドに記載があるlombok.addJavaxGeneratedAnnotation = false lombok.addLombokGeneratedAnnotation = true lombok.noArgsConstructor.extraPrivate = false lombok.anyConstructor.addConstructorProperties = true config.stopBubbling = truejjwt
一部のアルゴリズムを利用する際にJava11で廃止されたAPIに依存しているため、
Java8時点で利用していてJava11に移行してきた場合、依存関係を追加する必要がある
公式を参考に以下を追加するcompile('javax.xml.bind:jaxb-api:2.3.0') compile('com.sun.xml.bind:jaxb-core:2.3.0') compile('com.sun.xml.bind:jaxb-impl:2.3.0')その他
よしなに更新する
dependencies 以外で指定しているライブラリについても忘れず更新すること
jacoco の更新を忘れて時間を無駄にしましたJava11で廃止になったAPIに対応する
この記事を参考に廃止になったAPIを修正していく
SpringBoot2.0で廃止になったクラスを修正する
ビルドしてみるとSpringBoot周りで廃止されたクラスが複数出てくるので、それを修正していく
公式のマイグレーションガイドを参考にする今回はエラーメッセージを制御していた org.springframework.boot.autoconfigure.web 周りのクラスだけが対象だった
以下のメソッドを@RequestMapping(value = "/error") public ErrorResponse error(HttpServletRequest request, HttpServletResponse response) { ServletRequestAttributes attributes = new ServletRequestAttributes(request); Throwable error = errorAttributes.getError(attributes); return convertException(error); }こうする
@RequestMapping(value = "/error") public ErrorResponse error(WebRequest request) { Throwable error = errorAttributes.getError(request); return convertException(error); }テストしてみる
ここまでやるととりあえずビルドが通るようになるので、テストを回してデグレが起きていないか確認する
今回は特に問題なさそう
Warnの解消は後回しにして、とりあえずJDK11対応済みのアプリをDockerに固めてデプロイすることを目指すDockerfileを変更する
Dockerfileはベースイメージの変更だけでよい
どのイメージを選択すればいいかはこの記事が参考になる
今回はおすすめの通り、adoptopenjdk/openjdk11:alpine-slim を選択するFROM adoptopenjdk/openjdk11:alpine-slimその他
CircleCIの設定を変更する
CI/CDツールを利用している場合はそちらの設定も忘れず変更すること
テスト環境構築時のベースイメージの指定等、忘れがちSpringBootActuator
SpringBootActuatorで自動生成される全てのエンドポイントに/actuatorのprefixが追加されているので注意が必要
特に /health を利用しているとデプロイがうまくいかなくなる
その他の変更点はこの記事が参考になるさいごに
以上の修正でとりあえずデプロイできる状態にはなっているはずです
何か問題が起きれば適宜追記していきます
「こっちの書き方の方が正しい」「これだとバグる可能性がある」等あれば是非教えてください参考
mac上にhomebrewでAdoptOpenJDK11をインストール
Gradle wrapper のバージョン更新についてのメモ
Spring Boot 1.5.10 → Spring Boot 2.0.0 にしたときの覚書
Spring Boot 2.0 Migration Guide
Java 11 リリース後のオススメ Docker イメージを考える
Spring Boot 2.0のActuator、とりあえず動かすために知っておきたい変更点3つ
Javaエンジニアが Java 11 リリースに向けて備えておくべきこと
ObjectMapper can't deserialize without default constructor after upgrade to Spring Boot 2
- 投稿日:2019-12-19T13:04:57+09:00
SpringBoot1.5 + Gradle4.4 + Java8 + Docker 環境を JDK11 に対応させる
はじめに
Java8の無償サポートが2019年1月に切れてから一年ほど放置してましたが、
今回時間ができたので8以降初のLTSであるJava11への更新を行いました
その時のメモですと書き始めようとしましたが、OpenJDK8は2023年6月までサポートされるらしいので、
OracleJDKからOpenJDKに変えるだけでよかったのでは......
でもやってしまったので記録しときますJDKのアップデート
AdoptOpenJDK11をインストール
以下のコマンドを入れると最新のJDKがインストールされる
brew cask install adoptopenjdkしかし、現状ではJDK13が入ってしまうので、LTS版であるJDK11を入れるにはバージョンを指定する必要がある
ということで公開されているバージョンを検索$ brew search adoptopenjdk ==> Casks adoptopenjdk adoptopenjdk11-openj9-jre adoptopenjdk12-openj9 adoptopenjdk13-jre adoptopenjdk8 adoptopenjdk8-openj9-large adoptopenjdk10 adoptopenjdk11-openj9-jre-large adoptopenjdk12-openj9-jre adoptopenjdk13-openj9 adoptopenjdk8-jre adoptopenjdk9 adoptopenjdk11 adoptopenjdk11-openj9-large adoptopenjdk12-openj9-jre-large adoptopenjdk13-openj9-jre adoptopenjdk8-openj9 adoptopenjdk11-jre adoptopenjdk12 adoptopenjdk12-openj9-large adoptopenjdk13-openj9-jre-large adoptopenjdk8-openj9-jre adoptopenjdk11-openj9 adoptopenjdk12-jre adoptopenjdk13 adoptopenjdk13-openj9-large adoptopenjdk8-openj9-jre-large今回入れたいのはJDK11なので、以下のコマンドでバージョンを指定してインストール
brew cask install adoptopenjdk11すでに通っているPATHをJDK11に変更
export JAVA_HOME=`/usr/libexec/java_home -v 11`バージョンを確認
$ java -version openjdk version "11.0.5" 2019-10-15 OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.5+10) OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.5+10, mixed mode)IntelliJのProjectSDKにJDK11を指定
Command + ; でProjectStructureを開き、ProjectSDKとProjectLunguageLebelにJDK11を指定
Gradleをアップデート
Gradle4.4はJDK11に対応していないため、アップデートする必要がある
5.0以降のバージョンは対応しているようだが、折角なので現在の最新である6.0.1にしてみるgradle-wrapper.propertiesの更新
gradle/wrapper/gradle-wrapper.properties に記載されているバージョンを更新すればプロジェクトに適用されるGradleのバージョンが変更される
今回は以下の 4.4 の部分を 6.0.1 に変更するだけdistributionUrl=https\://services.gradle.org/distributions/gradle-4.4-bin.zipgradlewを更新
それだけだとgradlewに変更が伝播しないので、gradlewを生成し直す
./gradlew wrappergradle.buildを更新
各種フレームワーク・ライブラリをJDK11に対応したものに変更していく
基本的には全てgradle.buildに記載されているので、それを修正していけばよいJavaのバージョン指定を変更
各指定の意味は公式に記載されているので、必要な物を指定する
sourceCompatibility = 11 targetCompatibility = 11Gradle6系の記載方法に変更
jarの指定方法が変更になっているので更新
詳細は公式を参照のことjar { baseName = 'example' version = '1.0.0-SNAPSHOT' }上記だったものを以下に変更
bootJar { archiveBaseName = "example" archiveVersion = "1.0.0-SNAPSHOT" }SpiringBootのバージョンを変更
Java11を利用するにはSpringBoot2.1.x以上が必要
折角なので現在の最新である2.2.2にしてみる
基本的には公式のマイグレーションガイドに従えばいいbuildscript { ext { springBootVersion = '1.5.13.RELEASE' } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } }SpringBootが自動で依存関係管理プラグインを適用しなくなったので、プラグインも追加する
apply plugin: 'io.spring.dependency-management'メインクラスの指定方法が変わっているので、それも変更
springBoot { mainClassName = "jp.co.example.Application" }ライブラリのバージョンを更新
MavenRepositoryを見ながらライブラリのバージョンを更新していく
SpringBoot周りのライブラリ
SpringBoot周りのライブラリはバージョンを変数で指定しておくと楽
ただし、一部SpringBootのバージョンと異なる場合があるので注意が必要dependencies { compile("org.springframework.boot:spring-boot-starter-web:${springBootVersion}") compile("org.springframework.boot:spring-boot-starter-jdbc:${springBootVersion}") compile("org.springframework.boot:spring-boot-starter-security:${springBootVersion}") compile("org.springframework.boot:spring-boot-starter-actuator:${springBootVersion}") testCompile("org.springframework.boot:spring-boot-starter-test:${springBootVersion}") testCompile("org.springframework.security:spring-security-test:5.2.1.RELEASE") }lombok
lombokを利用している場合注意が必要
依存関係の指定方法が変わっているため、普通にバージョンだけ指定して更新するとビルド時にlombokで自動生成されるメソッドが見つからないとエラーが出る
公式を参考にして、以下の指定を追加するcompileOnly('org.projectlombok:lombok:1.18.10') annotationProcessor('org.projectlombok:lombok:1.18.10')その他
よしなに更新する
dependencies 以外で指定しているライブラリについても忘れず更新すること
jacoco の更新を忘れて時間を無駄にしました廃止になったクラスを修正する
ビルドしてみるとSpringBoot周りで廃止されたクラスが複数出てくるので、それを修正していく
公式のマイグレーションガイドを参考にする今回はエラーメッセージを制御していた org.springframework.boot.autoconfigure.web 周りのクラスだけが対象だった
以下のメソッドを@RequestMapping(value = "/error") public ErrorResponse error(HttpServletRequest request, HttpServletResponse response) { ServletRequestAttributes attributes = new ServletRequestAttributes(request); Throwable error = errorAttributes.getError(attributes); return convertException(error); }こうする
@RequestMapping(value = "/error") public ErrorResponse error(WebRequest request) { Throwable error = errorAttributes.getError(request); return convertException(error); }テストしてみる
ここまでやるととりあえずビルドが通るようになるので、テストを回してデグレが起きていないか確認する
今回は特に問題なさそう
Warnの解消は後回しにして、とりあえずJDK11対応済みのアプリをDockerに固めてデプロイすることを目指すDockerfileを変更する
Dockerfileはベースイメージの変更だけでよい
どのイメージを選択すればいいかはこの記事が参考になる
今回はおすすめの通り、adoptopenjdk/openjdk11:alpine-slim を選択するFROM adoptopenjdk/openjdk11:alpine-slimその他
CircleCIの設定を変更する
CI/CDツールを利用している場合はそちらの設定も忘れず変更すること
テスト環境構築時のベースイメージの指定等、忘れがちSpringBootActuator
SpringBootActuatorで自動生成される全てのエンドポイントに/actuatorのprefixが追加されているので注意が必要
特に /health を利用しているとデプロイがうまくいかなくなる
その他の変更点はこの記事が参考になるさいごに
以上の修正でとりあえずデプロイできる状態にはなっているはずです
「こっちの書き方の方が正しい」「これだとバグる可能性がある」等あれば是非教えてください参考
mac上にhomebrewでAdoptOpenJDK11をインストール
Gradle wrapper のバージョン更新についてのメモ
Spring Boot 1.5.10 → Spring Boot 2.0.0 にしたときの覚書
Spring Boot 2.0 Migration Guide
- 投稿日:2019-12-19T12:24:36+09:00
Docker コンテナを CGroup V2 なホストLinuxで動かす
Fedora 31 などでCGroup V2 (unified CGroup 階層) がデフォルトになっているので、そういうLinuxホストでpodman を用いて動かす話です。手順としてはUbuntu/Debian向けに書いてあります。fedora 31ならここに書いてあるように 作業すれば(下記の
podman-compose以外は)できるはずです。Project Atomic のAPTソースの設定
Ubuntuの場合(rootで)
apt-get install software-properties-common add-apt-repository ppa:projectatomic/ppaとすると
/etc/apt/sources.list.d/projectatomic-ubuntu-ppa-eoan.listが出来るので、それをエディタで開いてリリース名(eoanなど)をdiscoかbionicに変える。これは上記PPAがbionicとdiscoのパッケージしか用意していないからである。Debian Bullseyeの場合(rootで)
/etc/apt/sources.listの末尾deb [ allow-insecure=yes ] http://ppa.launchpad.net/projectatomic/ppa/ubuntu disco mainを追加。
Project Atomicからパッケージインストール (Ubuntu&Debian共通)
apt-get -t disco install buildah podman skopeo slirp4netns containernetworking-plugins(discoは前項のリリース名と同じにすること)crun のインストール
podman 標準のruncがCGroup V2非対応であるから、CGroup V2対応のcrunをインストールする。
Debian の場合
apt-get -t bullseye install crunUbuntu の場合
https://packages.debian.org/testing/main/crun からdebファイルをダウンロードして、
dpkg -iまたはgdebiを用いてインストールする。設定ファイルの変更
- https://github.com/projectatomic/registries/blob/master/registries.fedora の内容を
/etc/containers/registries.confにコピーする/usr/share/containers/libpod.confの中のruntime = "runc"の等号の右辺を"crun"に変更し保存する上記の作業で
docker ナントカのかわりにpodman なんとかと打てば同じことができる(ただしsudoではなくてrootログインが必要かも知れない)。一般ユーザーでのpodman使用は公式にはできることになっているがうまくいかなかった。podman-compose
docker-composeに対応するコマンドは上記の作業ではインストールされない。それでは困る場合pip3 install -U podman-composeを用いてpodman-composeコマンドをインストールする。CGroup V2なUbuntu Eoan上でLaTeXで年賀状を作る に示されたdockerコンテナをpodman-composeで動かし年賀状を作成することができた。
- 投稿日:2019-12-19T11:40:24+09:00
別ドメインのWebページのホストをdockerの力でEC2インスタンス1つに統合したときの話
このエントリは学生LT Advent Calendar 2019 25日目(最後)の記事です。
最後がこんなド初心者でいいのか分からない、誕生日なので許しておくれ
本エントリでは、いろんな辛さからWebページの配信をOS直下のnginxからdockerのnginxとかに移設した話をします。長いかも。
背景
1年以上前にドメインを取得して以降、用途に合わせて以下の2つのドメインにコンテンツを追加しています。
huequica.xyzブログ兼ポートフォリオworks.huequica.xyz作ったおもちゃを動かす場所この2つのドメインにコンテンツを配信するのに今までGitHub Pagesと自前で立てたEC2インスタンスに分断して配信を行っていました。
以下の図がわかりやすいかと思います。
さて、これを運用してきて半年以上が経過したところで幾つかのつらい事案を抱えることになりました。
なにがつらい?
以下の事情があり、けっこう悩みのタネになっていました。
GitHub Pages、単純にアップロードがしんどい
Jekyllでの生成、運用をしていた時期がありましたがデザインが気に入らなかったので自分ですべて生成しています。
そのため手元でコンテンツをBuildして、それをリポジトリに突っ込んでpushしてようやく公開される形になっていますが、ファイルパスが大文字小文字を識別していたり?とかで404が帰ってくることがあったりしてつらかったです。
最大の問題は pushする前の事前チェックができない ことで、pushしてはアクセスして確認みたいな地獄みたいなことをしていたので大変つらいです。マジで。
EC2インスタンスの環境が再現しづらい
某PHP製のWebアプリを開発した際、デプロイにVPS的なものが必要だった為とりあえずEC2インスタンスを取得していましたが、環境の不揃いが原因のバグが発生したりした為これもつらさの原因になっていました。
アプリケーションのビジネスロジックの問題ではなく権限エラーが大半のためFixがしづらく余計にしんどかったです。証明書の更新の自動化
調べるとCronでスクリプトを定期で回して更新させるパターンが多いみたいですが、手元で動かすのに失敗していたままほったらかしになっていた為手動更新をしていました。
おまけに毎回コマンドを忘れているので調べる手間もかかってダルい。これもつらかったです。
といった感じで環境を見直すには十分だろう、ということで以下の構成に変更しました。
おニュー環境
dockerであればMacやWindowsであっても簡単に環境を揃えることができ、また新しくドメインを増やす形でOSSのSaaSサービスを展開することも簡単にできるようになります。そのため今回docker、及び管理を楽にするためにdocker-composeを使いました。
構成は超短的に表すと以下になります。
今回の場合
huequica.xyzとworks.huequica.xyzの2つのドメインの行き先をEC2の1つに集中させ、URLで識別してdockerコンテナの中のnginxに流しています。ただし、dockerの中にはHTTPアクセスを識別して仕分ける(リバースプロキシ)みたいな機能は無いのでそっちは別で用意することになります。ここで出てくるのが nginx-proxyです。
nginx-proxy
nginx-proxyはリバースプロキシの仕組みを超簡単に導入するためのdockerイメージです。
ここからは実際のdocker-compose.ymlと図を交えて説明します。実際のコンテナ構成
まずはHTTPの仕分け役をしている
proxyのymlから見ていきます。proxy/docker-compose.ymlversion: "3.5" services: nginx-proxy: container_name: nginx-proxy image: jwilder/nginx-proxy ports: - 80:80 - 443:443 volumes: - /var/run/docker.sock:/tmp/docker.sock:ro # nginx-proxy-companionに共有させる - certs:/etc/nginx/certs:ro - vhost:/etc/nginx/vhost.d - html:/usr/share/nginx/html networks: - proxy-network labels: - "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy" # SSL証明書発行しないのであれば不要 letsencrypt-nginx: container_name: letsencrypt-nginx image: jrcs/letsencrypt-nginx-proxy-companion privileged: true depends_on: - nginx-proxy volumes: - certs:/etc/nginx/certs:rw - vhost:/etc/nginx/vhost.d - html:/usr/share/nginx/html - /var/run/docker.sock:/var/run/docker.sock:ro restart: always volumes: certs: vhost: html: networks: proxy-network: name: proxy_networkキモになるのはこの3つです。
networksの項目で他のディレクトリのdocker-composeとの連携場所を作るnginx-proxyには上述のネットワークに所属させる- SSL証明書を発行する場合は
volumesを共有させる(していないと警告が出る)
次に
portfolioのymlです。portfolio/docker-compose.ymlversion: "3.5" services: app: container_name: portfolio_nginx image: nginx volumes: - ./content:/usr/share/nginx/html - ./conf.d:/etc/nginx/conf.d - ./nginx.conf:/etc/nginx/nginx.conf environment: - VIRTUAL_HOST=huequica.xyz - LETSENCRYPT_HOST=huequica.xyz - LETSENCRYPT_EMAIL=hoge@dogemail.com networks: - proxy-network networks: proxy-network: name: proxy_network
environmentの項目でVIRTUAL_HOSTという見慣れない変数を作っていますが、これが一番大事です。
具体的には、前述のnginx-proxyが拾ったHTTPはVIRTUAL_HOSTのアドレスを元に制御してレスポンスを中継します。そのため、ローカルで稼働させる場合はlocalhostに書き換えるなどしないとなりません。また、先程の
proxy内でSSL証明書用のコンテナを入れている場合はLETSENCRYPT_HOSTとLETSENCRYPT_EMAILを追加するとSSL証明書の取得、定期更新を自動で行います。あとは
proxyで設定したnginx-proxyのいるネットワークに、コンテンツ配信用のnginxコンテナを所属させることも必要になります。
さきほどとあんまり変わりませんが、
worksの方のymlも掲載しておきます。works/docker-compose.ymlversion: "3.5" services: works_nginx: container_name: works_nginx image: nginx volumes: - ./content:/usr/share/nginx/html - ./conf.d:/etc/nginx/conf.d - ./nginx.conf:/etc/nginx/nginx.conf environment: - VIRTUAL_HOST=works.huequica.xyz - LETSENCRYPT_HOST=works.huequica.xyz - LETSENCRYPT_EMAIL=hoge@dogemail.com networks: - proxy-network networks: proxy-network: name: proxy_networkworksもやることは同じです。
VIRTUAL_HOSTとLETSENCRYPT_HOSTにドメインを設定して、LETSENCRYPT_EMAILに更新用のメールアドレスを渡してやるだけです。ただし、PHPやRubyのコンテナと連携して動的なものを返そうと考えている方はそのコンテナとnginxコンテナのみをつなぐ為のネットワークの新設、所属が必要になるのでそれだけ注意してください。
これによって解決したこと
- 事前のコンテンツチェックができるようになった
- 証明書が自動更新になり、定期更新など何も気にしなくて良くなった
- 環境の統一がとれたことにより、デバッグがすこぶる楽になった
- GitLabなどを自前で動かすこともできるようになった
などなど、夢が広がりまくりです。dockerに感謝
これからの課題
いままでworksで配信していたクソアプリがAPIと静的コンテンツの2分化の必要がありそうな気がしてきているのでそれのコード改修などがあります。なので、Rubyコンテナをworksの
docker-compose.ymlに追加してとかしなければなりません…最後に
誕生日プレゼント、待ってます。
https://www.amazon.jp/hz/wishlist/ls/3FGFSE5EZKEM3?ref_=wl_share
- 投稿日:2019-12-19T10:49:02+09:00
Slurm HPCクラスタとKubernetesを同居させてみた(後編)
はじめに
こんにちは、(株)日立製作所 研究開発グループ サービスコンピューティング研究部の小林です。
本日のアドベントカレンダーは、HPCジョブスケジューラ
SlurmとコンテナオーケストレータKubernetesの同居クラスタを構築する投稿の後編です。Singularityベースのワークロードを双方から実行可能な環境を構築しきり、サンプルプログラムを実行してみます。アドベントカレンダーではHPCジョブスケジューラの一つである
PBSに関する記事もあるので興味がある方は要チェックです。手順
概要
構築手順の概要を示します。本日は
手順2以降を紹介します。前回の投稿はこちらです。
- Slurmクラスタを構築する
- マスタ/ワーカ共通準備
- Slurmマスタの構築
- Slurmワーカの構築
- Singularityを導入する (本日はここから)
- K8sクラスタを構築する
2. Singularityを導入する(マスタ/ワーカ共通)
ここではコンテナランタイムの
Singularityを導入します。コンテナランタイムと一口に言っても、高レイヤと低レイヤの2つがあります。Singularityはコンテナ自体の操作を提供する低レイヤのランタイムを指しますが、ここではKubernetesなどとのコンテナオーケストレータ向けにAPIを提供する高レイヤのランタイムとしてSingularity-CRIも含めます。2.1. Singularityの導入
基本的には公式のインストールページを参考にします。執筆当時の最新バージョンは
v3.4.0です。執筆当時のGO最新版はv1.14ですが、さしあたり筆者が使い慣れたv1.13をGOの公式を参考にインストールしています。
# 依存するツール・ライブラリのインストール sudo apt-get install -y \ build-essential \ libssl-dev \ uuid-dev \ libgpgme11-dev \ squashfs-tools \ libseccomp-dev \ wget \ pkg-config \ git \ cryptsetup-bin # GO1.13のインストール sudo add-apt-repository ppa:longsleep/golang-backports && \ sudo apt-get update && \ sudo apt-get install -y golang-go次に
Singularityをインストールします。git clone https://github.com/sylabs/singularity.git && \ cd singularity && \ git checkout v3.4.0 ./mconfig && \ make -C ./builddir && \ sudo make -C ./builddir install sudo apt-get install -y socat2.2. Singularity-CRI(Sycri)の導入
続いて
Sycriを公式のGitHubを参考にインストールします。git clone https://github.com/sylabs/singularity-cri.git && \ cd singularity-cri && \ git checkout tags/v1.0.0-beta.5 -b v1.0.0-beta.5 && \ make && \ sudo make install
Sycriサービスはデーモンとして起動させるので公式ページを参考にサービスファイルを/etc/systemd/system/sycri.serviceに追加します。[Unit] Description=Singularity-CRI After=network.target StartLimitIntervalSec=0 [Service] Type=simple Restart=always RestartSec=1 ExecStart=/usr/local/bin/sycri Environment="PATH=/usr/local/libexec/singularity/bin:/bin:/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin" [Install] WantedBy=multi-user.targetサービスを起動します。
sudo systemctl start sycri && sudo systemctl enable sycri実行後、
sycriサービスが正常起動しているか確認します。sudo systemctl status sycri3. K8sクラスタを構築する
最後にKubernetesクラスタを構築します。手順はUbuntuへのK8sインストール記事の
Step. 3-6を参考にしています。
ただしこの記事ではコンテナランタイムがDockerになっているのでSingularityの公式ページを参考に修正します。3.1. マスタ/ワーカ共通準備
Kubernetesレポジトリをaptに追加します。curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add sudo apt-add-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main" sudo apt-get install -y kubeadm kubelet kubectl
Kubernetesの実行に必要なサーバ設定を施します。
下記のSwapの停止に関してはサーバ再起動後も設定が維持するために/etc/fstabを修正する方法もあります。# Swapの停止 sudo swapoff -a # NW周りの設定. lsmodの結果が何も表示されなければmodprobe以下を実行 lsmod | grep br_netfilter sudo modprobe br_netfilter sudo cat /proc/sys/net/bridge/bridge-nf-call-iptables # 1が出力されることを確認 sudo cat /proc/sys/net/bridge/bridge-nf-call-ip6tables # 1が出力されることを確認 sudo sysctl net.ipv4.ip_forward=1コンテナランタイム変更設定を
/var/default/kubeletに追加します。KUBELET_EXTRA_ARGS=--container-runtime=remote \ --container-runtime-endpoint=unix:///var/run/singularity.sock \ --image-service-endpoint=unix:///var/run/singularity.sock3.2. K8sマスタの構築
Kubernetesマスタサーバ関連のサービスを起動します。執筆者環境では
CRIとPodネットワークのCidrを指定をする必要がありました。また、Sycriサービスが正常に起動していることを確認してください。sudo kubeadm init --cri-socket unix:///var/run/singularity.sock --pod-network-cidr=10.92.0.0/16コマンドが正常に終了すればワーカで実行すべきコマンド例が出るのでメモします。
> kubeadm join 192.168.X.Y:6443 --token 111aaa.9999xxxxxxx \ --discovery-token-ca-cert-hash sha256:XXXXXXXXXXXXXXXKubectlを利用するためのコンフィグを整備します。これも
kubeadmが正常終了すると出力されます。mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config試しに
kubectl get svcなどを叩いてエラー以外が帰って来ることを確認します。3.3. K8sワーカの構築
マスタで得られた
kubeadm join hogehogeコマンドに--cri-socket unix:///var/run/singularity.sockを加えて実行します。kubeadm join 192.168.X.Y:6443 --token 111aaa.9999xxxxxxx \ --discovery-token-ca-cert-hash sha256:XXXXXXXXXXXXXXX \ --cri-socket unix:///var/run/singularity.sock3.4. CNIの設定
K8sではL2 over L3ネットワーク構築のためにCNI(今回はCalico)を導入する必要があります。CNIを導入することで、現状はkubectl get pod --all-namespacesを実行するとpending状態のcorednsも有効になります。通常はCNI導入は
kubectlコマンド一発で入る場合が多いのですが、今回の環境ではCNIが利用するいくつかのパスがインストールに伴い作成されずCNIが立ち上がりませんでした。そこで以下のコマンドを先にマスタとワーカの両方で実行しておきます。sudo mkdir -p /var/lib/cni/networks && \ sudo mkdir -p /ect/cni/net.d && \ sudo mkdir -p /var/lib/calico && \ sudo mkdir -p /run/calico && \ sudo touch /var/lib/calico/nodenameまた、マスタとワーカの両方で
Hostnameの設定も/etc/hostnameと/etc/hostsでなされているか確認します。
特に/etc/hostsでは以下のようにします。127.0.0.1 localhost.localdomain localhost 127.0.1.1 YOUR_HOSTNAME # 適宜ホスト名に変更最後に
Calicoをインストールします。kubectl apply -f https://docs.projectcalico.org/v3.8/manifests/calico.yaml
CalicoやCoreDNSコンテナが起動しない場合は、kubectl logs SOME_POD_NAMEやkubectl describe pod SOME_POD_NAMEで原因を追求して対応します。コンテナイメージがPullできない場合にはCalicoコンテナやCoreDNSのlogや各ノードのJournalを参照してコンテナ利用するパスの有無や権限を適宜変更します。以上の手順を実行すると、
Slurmコマンドであるsinfoと、kubernetesコマンドであるkubectlが同居した環境を構築できます。使ってみる
Slurm with Singularity
このサイトを参考にSingularityコンテナをSlurmから実行してみましょう。コマンドはマスタサーバから実行しています。
まずは利用可能なSlurmのパーティションを確認します。
sinfo > PARTITION AVAIL TIMELIMIT NODES STATE NODELIST debug* up infinite 1 idle koba-slurm2
debugという名前のidle状態のパーティションがワーカノードに割り当てられていることがわかります。次にSlurmのジョブスクリプトsingularity.sbatchを定義します。上の参考サイトのスクリプトについて、パーティション#SBATCH -pと実行するsingularityコマンドを改変しています。#!/bin/bash #SBATCH -J singularity_test #SBATCH -o singularity_test.out #SBATCH -e singularity_test.err #SBATCH -p shared #SBATCH -t 0-00:30 #SBATCH -N 1 #SBATCH -c 1 #SBATCH --mem=4000 # Singularity command line options singularity pull --name hello-world.sif shub://vsoch/hello-world singularity exec hello-world.sif cat /etc/os-release実行してみます。
sbatch singularity.sbatch結果をNFSなどに出していない場合、ジョブが実行されたノード上に出るのでワーカノードにログインしてホームディレクトリを見ると
singularity_test.outとsingularity_test.errがあります。
Slurmによるジョブ制御とSingularityのコンテナ実行が連携できていることがわかります。Kubernetes with Singularity
K8sについては
Sycriのユーザドキュメント 7.1.を参考にしてみましょう。
こちらもマスタノードで実行します。これまでの手順を行うとサーバ上に
SycriのGitレポジトリクローンがあると思います。リポジトリのexample/k8s/hello-kubernetes.yamlを利用します。kubectl apply -f examples/k8s/hello-kuberentes.yaml kubectl get pod # > hello-kubernetes-8764bc78f-86t2x 1/1 Running 0 2m10s # > hello-kubernetes-8764bc78f-nq2pb 1/1 Running 0 2m10s # > hello-kubernetes-8764bc78f-xjrxx 1/1 Running 0 2m9s
kubectl get svcでサービス公開されたポートを確認し叩いてみるとサービスが提供できていることがわかります。curl koba-slurm2:SOME_PORT # > Hello, World!まとめ
以上の手順で
SlurmとKubernetesがSingularityのワークロード実行可能な環境を構築できました。現状はこのような実行環境のユースケースは少ないと思いますが、将来的にHPCWireの記事で期待されているような
新しいAIワークロードのニーズが生まれるかもしれませんし、
その際には単なる同居ではなくHPCジョブスケジューラとKubernetes双方のジョブスケジューリングを統合する機能が必要になる可能性があります。
SylabsのGitHub/WLM Operatorとみなすこともできるかもしれませんね。今後の関連動向についても引き続き情報発信をしていきたいと思います。
- 投稿日:2019-12-19T10:30:45+09:00
Slurm HPCクラスタとKubernetesを同居させてみた(前編)
はじめに
こんにちは、(株)日立製作所 研究開発グループ サービスコンピューティング研究部の小林です。
DockerやKubernetesに代表されるコンテナ技術がWebアプリ開発を始め様々な場面で使われるようになりました。最近ではHPC向けのコンテナランタイムとして
Singularityが開発され、より一層コンテナ活用の幅が広がりそうですね。本日のアドベントカレンダーでは、HPCジョブスケジューラの一つである
SlurmクラスタとコンテナオーケストレータのKubernetesクラスタを同居させSingularityベースのワークロードを双方から実行可能な環境を構築してみます。アドベントカレンダーではHPCジョブスケジューラの一つである
PBSに関する記事もあるので興味がある方は要チェックです。なぜ同居させるのか
データ分析技術の多様化
従来のデータ分析に関するいくつかの主要な動向として、HPCクラスタを用いた大規模バッチ処理や並列同期型のシミュレーションなどが挙げられます。また、新しいデータ分析の潮流として機械学習や深層学習も一般的になりつつあります。
機械学習に関する技術開発は近年一層活発に行われ、開発技術がコンテナイメージとして公開されています。更にはコンテナのスケーラビリティや可搬性/再現性を最大化するコンテナオーケストレータとしてKubernetesが台頭し、コンテナを用いた機械学習のワークフローを管理するKubeflowなどの便利技術なども続々と開発されています。HPCジョブスケージューラへのコンテナ統合
一方で、従来のHPCクラスタを用いたバッチ/パラレルジョブに
コンテナ技術を取り入れる動きがあります。HPCジョブスケジューラの一つであるSlurmではコンテナ化されたジョブの実行をサポートし始めたり、HPCでの実行を想定したコンテナランタイムであるSingularityなども登場したことを受け、HPCジョブスケジューラとコンテナの距離は縮まっています。HPCジョブとコンテナアプリのワークロード統合
更には、Kubernetes側からも従来のHPCジョブとコンテナベースの処理のワークロード統合を示唆するブログ記事や、Singularity用のKubernetes対応コンテナランタイムインターフェース(CRI)としてSingularity-CRIが開発されています。
特に、Singularity-CRIの登場により、HPCクラスタの多量のリソースの以下のような柔軟な活用が可能になります。
- 従来のHPCジョブ実行
- 実験作業の再現性確保が容易なコンテナベースのHPCジョブ実行
- GPUなどの潤沢なリソースを投入した高スケールなコンテナベースのデータ分析
構成
SlurmとKubernetes(K8s)の同居クラスタを作ります。UbuntuベースのマスタサーバにはSlurmとK8sのマスタとして役割を、ワーカサーバには同じくSlurmとK8sのワーカとしての役割を実行させます。
また、K8sのコンテナランタイムには、一般的なDocker(Containerd)ではなくSingularityを使います。
手順
概要
手順の概要を示します。マスタサーバとワーカサーバではデーモンや依存ソフトで共通するものも多いので、作業が分岐する場合は適宜言及します。
- Slurmクラスタを構築する
- Singularityを導入する(マスタ/ワーカ共通)
- Singularityの導入
- Singularity-CRI(Sycri)の導入
- K8sクラスタを構築する
- マスタ/ワーカ共通準備
- K8sマスタの構築
- K8sワーカの構築
- CNIの設定
1. Slurmクラスタを構築する
1.1. マスタ/ワーカ共通準備
Slurmサーバの構築方法は公式のQuickStartを参照します。
依存ツールのライブラリが足りないエラーが起きたのでこちらのサイトも参考にしています。まずは認証用のMUNGEをインストールします。
sudo apt update sudo apt install -y munge libmunge-dev libmunge2 sudo systemctl start munge && sudo systemctl enable munge
MUNGEはデーモンを起動すると認証用の秘密鍵を/etc/munge/munge.keyに作成します。この秘密鍵はSlurmクラスタのマスタ・ワーカで共通のものを使うので1.3.にてマスタの鍵をコピーします。また、MUNGEは/var/log/munge以下にログを出力しますが、フォルダ所有者がユーザMUNGEでない場合起動に失敗する場合があります。最新版のSlurmを入手してインストールします。執筆時点での最新版は
slurm-19.05.4です。
インストール前に、依存するライブラリ等を導入していきます。sudo apt install -y build-essential python続いてSlurmをソースコードからビルドします。ビルド後に
MUNGEのライブラリに参照できないエラーが出たのでconfigureのフラグを追加しました。wget https://download.schedmd.com/slurm/slurm-19.05.4.tar.bz2 tar --bzip -x -f slurm*tar.bz2 cd slurm-19.05.4 sudo ./configure --with-munge="/usr/bin/munge" sudo make && sudo make install
Slurm関連のサービスファイルを/etc/systemd/system/以下にコピーします。sudo cp /home/ubuntu/slurm-19.05.4/etc/*.service /etc/systemd/system/また、公式のSuper Quick Startの
7 NOTEにあるように、Slurm用のユーザを作成します。sudo adduser slurmSlurmユーザは、
/var/run/spool,/var/log/syslogへの参照や書込権限が必要なのでグループなりユーザに権限を付与します。環境によってポリシーが異なると思いますが、rootグループなどにslurmユーザを加えて適宜必要なフォルダにグループ権限を与えるなどの対応があると思います。1.2. Slurmマスタの構築
Slurmマスタサーバを構築します。構築前にMUNGEサービスが正常に動いていることをsystemctl status mungeなどで確認しておきましょう。
マスタサーバ構築では、Slurmクラスタのコンフィグ作成が主な作業になります。コンフィグの作成はSlurmが提供するWebGUIに必要事項を入力して出力されるファイルを/usr/local/etc/slurm.confに配置します。私はUbuntuサーバ版を入れてしまったので、他のPCからブラウザアクセスして作成することにしました。設定のためだけに
apache2を入れてhttp://HOSTNAME:80/html2/configurator.easy.htmlにアクセスします。sudo apt install -y apache2 sudo ln -s /home/ubuntu/slurm-19.05.4/doc/html /var/www/html/html2サーバの設定に必要なリソース情報は下記のコマンドで適宜取得します。
# CPU関連 lscpu | grep -E '^Thread|^Core|^Socket|^CPU\(' > CPU(s): 2 > Thread(s) per core: 1 > Core(s) per socket: 1 > Socket(s): 2# メインメモリ関連 free -m > total used free shared buff/cache available > Mem: 7976 102 5514 0 2359 7570 > Swap: 0 0 0ひとしき入力し終えたら
submitボタンを押して得られる情報を/usr/local/etc/slurm.confとして出力します。
マスタサーバではslurmctldをサービスとて起動します。sudo systemctl start slurmctld && sudo systemctl enable slurmctld起動後に
Can't open PID file /var/run/slurmctld.pid (yet?) after start: No such file or directoryなどのエラーが出る場合がありますが、適宜ユーザやフォルダの権限を見直します。1.3. Slurmワーカの構築
ワーカで実施するべき作業は大きく2つです。
MUNGEの秘密鍵をマスタサーバから入手し利用Slurmのコンフィグをマスタサーバから入手し利用作業がうまく行かない場合は、マスタサーバとワーカサーバの
MUNGEサービスやslurm関連サービスがキチンとActiveになっているか適宜確認します。
MUNGEインストール後、マスタサーバのmunge.keyをコピーしてMUNGEサービスを再起動します。sudo scp SOME_USER@SLURM_MASTER:/etc/munge/munge.key SONE_USER@SLURM_WORKER:/ect/munge/munge.key sudo systemctl restart mungeエラー無くサービスが起動できたことを確認します。
Slurmをインストール(サービスファイルのコピー含め)したのち、
Slurmコンフィグをコピーして利用します。sudo scp SOME_USER@SLURM_MASTER:/usr/local/etc/slurm.conf SONE_USER@SLURM_WORKER:/usr/local/etc/slurm.conf sudo chown root:root /usr/local/etc/slurm.conf sudo start slurmd && sudo systemctl enable slurmdここまで完了し、
SlurmマスタサーバでMUNGEとSlurmCtldが、ワーカサーバでMUNGEとSlurmdが正常稼働していること確認してからマスタサーバでsinfoを実行します。AVAILがupならSlurmクラスタの起動完了です。sinfo > PARTITION AVAIL TIMELIMIT NODES STATE NODELIST > debug* up infinite 1 idle test-slurm2前編のおわりに
本日の投稿では
SlurmとKubernetesの同居クラスタ構築に関して、システム構成とSlurmクラスタの構築手順を紹介しました。後編の投稿ではSingularityとSingularity-CRIを利用して稼働するKubernetesクラスタの構築手順とクラスタのサンプル実行を紹介したいと思います。
- 投稿日:2019-12-19T09:45:49+09:00
SAP CP(トライアル) の CF で Docker を使ってみようとしたら、うまく行かなかった話
はじめに
この記事は SAP Advent Calendar 2019 の12月19日分の記事として執筆しています
こんにちわ、株式会社KYOSOでエンジニアをしている上田といいます。
よろしくおねがいします。本記事は、Cloud Foundry は、 Docker Image に対応していると聞いて
SAP Cloud Platform へデプロイを試みて失敗したときのトラブルシュートです。デプロイが出来ない理由は、
トライアル環境で試したから!と推測するまでの問題点と解決策をまとめました。トライアル以外の環境での実施、またはトライアル環境であっても時期次第で成功する可能性があることをご理解ください。
「いやいや、自分はトライアル環境でも成功したよ!」と言った成功体験等ございましたら
お話等伺えましたら嬉しく思います。環境
- SAP Cloud Platform( trial ): Cloud Foundry
- PC: Macbook Pro(2017)
- CFコマンド: cf version 6.35.2+88a03e995.2018-03-15
問題1
cfコマンドの接続先(API エンドポイント)が間違っている
自分の場合、会社のCloudFoundry環境 を利用していたこともあり
cfコマンドは、トライアルとは別のAPIエンドポイントに接続している状態でした。解決策
以下のコマンドで APIエンドポイントの変更すれば解決
cf login -a <APIエンドポイントのURL>または
cf api <APIエンドポイントのURL> cf loginAPIエンドポイントのURLは、SAP Cloud Platform Cockpit から確認出来ます。
問題2
cf コマンドを実行した際のエラー内容が不明
解決策
CF_TRACE=trueを環境変数に設定して、詳細なログが見えるようにする。環境変数
CF_TRACEの値をtrueにすると、
CloudFoundry を操作するためのAPI呼び出しが見えるようになるので
どのステップでエラーが発生しているのか、コンソール上に表示されます。問題3
SAP CP で Docker Image のデプロイが出来ない
解決策
以下のコマンドで、Diego( Cloud Foundry のコンテナ管理システム )を有効にする。
cf enable-feature-flag diego_dockerトライアル環境では、初期状態として Diego が無効な状態のようで、明示的に有効化する必要があるようです。
※このコマンド実行時に権限不足で実行出来ないことが発覚、 トライアル環境では Docker Image の利用は出来ないと判断しました。。。エラー内容
最後に
流石にトライアル環境で Docker 利用は考えが甘かったかなと反省しつつ
自分が遊ぶ環境を会社に買ってもらえないかチラ見する所存です。参考URL
- 投稿日:2019-12-19T06:58:19+09:00
Dockerの立ち上げ、まだコピペでやってるの?ちゃんと理解したくない?
はじめに
詳しい人には気になる表現があるかもしれませんが、どうか気にしないでください
この記事は、Dockerで開発環境を構築したいけど、 いつもコマンドコピペでやっていて実はよくわかってない!! という方に向けて、細かーいところをふんわりと解説したいというモチベーションで書いています。
ここでは、サンプルとしてNode.jsの環境を取り上げます。Node.jsは、JavaScriptのフレームワークですね!Vue.jsの開発などでも大活躍のフレームワークです!
Dockerを使うモチベーション
世の中には便利な開発環境がたくさんありますね。Node.jsもそのひとつです。この賢い人をインストールしてあげるだけで、簡単便利な開発環境ができあがります。
では、この席をどこに用意するといいのでしょうか?
ご自身の PC に環境を整えて上げてもいいのですが、この手のフレームワークはいろいろな部品群との連携がとても大切になっており、またそれらのバージョンを揃えてあげることが大切です。そんなときには、 Docker でご自身のPCを汚さず、 Node.js ちょっと飽きたなー、違ったなー、というときに、いつでも綺麗サッパリできるようにしましょう、
Docker 環境を作る
Docker 自体のの詳しい説明はここでは避けます。ご自身の PC を綺麗に保つために、いつでも綺麗サッパリできるような受け皿を、 PC 上に構築してあげる仕組みです。 Docker を使う上では、イメージとコンテナを知っておく必要があります。ちょっと調べてみたところ、
- イメージ : 開発環境の土台となる情報が詰まったもの
- コンテナ : イメージから作った開発環境
という感じの書き方がされたサイトがいくつか見つかりました。
個人的に、よくわからなかったので、私なりの解釈をしてみました。こんな感じです。
- イメージ : OSのインストールDVD、工場出荷時に戻すときに使うDVD
- コンテナ : 空のパソコン買ってきて、DVDでOSをインストールした状態、または買ってきてすぐのパソコン
Dockerfile を用意する
Dockerfile は、Docker イメージをどう定義するか、そのイメージをコンテナにするときについでにやっておいてほしい設定、などを書いておき、上から順に全部ガーーーッとやっちゃってくださいという、台本みたいなもの。パソコン屋さんにカスタマイズをお願いする注文書みたいな感じでしょうか。
この OS 入れて〜 このソフト入れて〜 ネットワークの設定はこんな感じで〜 スタートアップの設定はこれで〜という感じのことを書きます。
Dockerfile の書き方
ベースのイメージを決めよう
Dockerfileは基本文法として
命令 引数
のペアで書いていきます。ツラツラと書き下し、上から順に実行するというものです。
まずベースとする Docker Image を決めます。
まず、Node.jsは、それを何に使うのかによって、どのバージョンを使うのか、考えた方が良いです。例えばVue.jsの開発用として使いたいのであれば、Vue.jsのサイトで、推奨バージョンが確認できると思います。とりあえずなんか入れてみよう、ということで、ここではVue.jsを対象として書いてみます。バージョンは適宜必要なものに変えてもらうと良いと思います。
Dockerfile にまず次の一行を書きましょう。FROM node:8.16.1-alpineこれは node を DockerHub で探してきて、 8.16.1-alpine というタグがついているイメージをプルしてきてください。という注文です。
ここまでで新出単語が3つほどありましたね。ひとつづつ確認します。
node.js
- JavaScript の実行環境です。 JavaScript はブラウザが解釈してほげほげするというのが昔からのやり方で、ブラウザによって解釈の仕方が違うから困った困ったという歴史があり、そこから ECMAScript という共通化の動きが云々カンヌン…。そうやってブラウザ側は共通化できて JavaScript が定着してきたけど、サーバーサイドは相変わらず Java とか PHP とか覚えないといけないのか…。という悲しい人を増やさないよう、「あなたの使える JavaScript をサーバーでも使えるようにしてあげるよ」という優しい仕組みが Node.js です。 Node.js はクライアントサイドでもサーバーサイドでも共通して JavaScript を使えるようにしてくれるので、 Node.js をベースとしたフレームワークは数多くあります。
DockerHub
- Docker イメージを公開しているサービスです。いろいろな開発環境をサクッと用意できるよう、ある程度出来上がったイメージがたくさん用意されています。 Docker 公式のサービスなので、 Dockerflie からサクッと取得できます。
alpine
- 軽量 Linux ディストリビューションのひとつです。世の中にはたくさんの Linux があります。そんな中、これまではあまり注目されていなかったのですが(たぶん)、 Docker の普及とともに、コンテナ単位のサイズを節約できる 軽量 Linux ディストリビューションが日の目を見ました。その代表格が alpine です。
セットアップしよう
ここからは alpine Linux が動作している PC を CUI で使っているんだ・・・・!!という想像をしながら書いていきます。 CUI はいわゆる黒いアイツです。
まず、今後の作業をするディレクトリに入ります。
WORKDIR /appWORKDIR は、いま居るディレクトリを変更してね、という命令です。
/app ディレクトリに入ったら、 Vue-cli をインストールします。ここでは、Vue.jsの環境を例に挙げているので、後でDockerを動かすサンプル用に、Vue-Cliを入れます。
RUN apk update &&\ npm install -g npm vue-cliRUN は以降のコマンドを CUI で実行してね、という命令です。
- apk
- alpine Linux で採用されているパッケージマネージャーです。パッケージマネージャーは、有名ドコロのツールたちを管理してくれる便利なお方です。整理整頓をしてくれるお優しいお方です。
- npm
- Node.js 関連のパッケージマネージャーです。こちらも整理整頓をしてくれるお方です。 Node.js 関連が専門です。
つまり、
apk updateでパッケージマネージャー apk を最新の状態にして、
npm install -g npm vue-cliで vue-cli をインストールします。
-g はグローバル指定のことですが、 Node.js のプロジェクトの説明をしないといけないので、一旦気にせず行きましょう。ちなみにこの npm ですが、 node.js のイメージを選んだ時点で最初から入っているのですぐに使うことができるのです。突然出てきたと、びっくりしないで大丈夫です。ポートの開放
今回例に挙げている Vue.js は Web アプリの開発環境です。つまり、 Web サーバーとして動作し、ブラウザからアクセスできるような感じにしていきます。そのため、 Docker コンテナで動いている alpine Linux と、ご自身の PC とをつないであげる必要があります。それぞれは別のマシンとして動いているので、お互いが情報をやり取りできるようにして上げる必要があります。こういう場合、ポートを開放してあげることで Vue.js で作った Webアプリ をご自身の PC のブラウザからチェックすることができるようになります。Node.jsはWeb系で使われることが多いので、多くのケースでこの設定は必要なのではないでしょうか。
このポート番号は何番でもいいのですが、とりあえず9000番を開けておきます。
dockerfileEXPOSE 9000Dockerfile完成
これまでのことをまとめると、次のDockerfileが完成します。
dockerfileFROM node:8.16.1-alpine WORKDIR /app RUN apk update &&\ npm install -g npm vue-cli EXPOSE 9000しかし、このままではコンテナは出来上がっても何もできません。起動しても何もプログラムが動いていない状態です。つまり、何もできません。そこで、コンテナ側でシェルを用意しておき、あとからそこにつないで上げることで、手元の PC からコンテナを操作することができます。
これは次の一行で OK です。CMD ["/bin/sh"]あらためてまとめると
dockerfileFROM node:8.16.1-alpine WORKDIR /app RUN apk update &&\ npm install -g npm vue-cli EXPOSE 9000 CMD ["/bin/sh"]となります。これを適当なエディタで記入し、 Dockerfile という名前で保存しておきます。
Dockerfile をビルドしてローカルに Docker イメージを作る
Dockerfile はカスタマイズ用の注文書と言いました。注文書ができあがったので、注文書どおりにセットアップDVDをつくってあげましょう。これを入れたら工場出荷時にもどるよ、というようなDVDです。
$ docker build -t vue_app_image .ここで急に
dockerというコマンドが登場しました。そうです、 Docker を動かすには、 Docker をインストールする必要があるのです(当たり前)。Docker のインストールはいろいろな先人の知恵を借りてなんとか攻略してください。 Docker for Mac とか Docker for Windows とかいろいろ便利になっているので、簡単にできるはずです。では、コマンドの説明をします。
dockerは Docker を使うぜ、というだけです。buildは Dockerfile に従って作業するぜ、というコマンドです。-tは タグ付けするぜ、という意味です。 --tag です。vue_app_imageは完成したイメージのタグの名前です。自由に決めることができます。.は打ち間違えではありません。いまいるディレクトリにある Dockerfile を使うよ、という意味です。つまり、これまでに用意した Dockerfile がおいてある場所でこのコマンドを実行する必要があります。(パスを入れればどこからでもできますが、この方が簡単です。無事に成功すると、 Docker イメージが出来上がります。イメージが出来ているかどうかは、次のコマンドで確認することができます。
$ docker image -lsDocker イメージを使って、 Docker コンテナを作る
Docker イメージというセットアップ DVD みたいなものができたので、 パソコンを用意してインストールしてあげましょう。これが Docker コンテナをつくるということです。パソコンをいっぱい買えば(コマンドを何回も実行すれば)環境はいっぱい作れます。
$ docker run -v `pwd`:/app -p 9000:9000 --name vue_app -it -d vue_app_imageまたコマンドの解説をします。
dockerは Docker を使うぜ、ということです。(もういい)runはコンテナを作るぜ、ということです。-vは volume の意味です。ご自身の PC の特定のディレクトリと、コンテナ内の特定のディレクトリを紐付けることで、ファイルの編集をどちらでもできるようにします。pwdは Unix 系 OS でよく使われるコマンドです。今いるディレクトリのパスを取得することができます。 Print Working Directory という意味です。:これは -v オプションと連携しており、 : の前に指定したディレクトリをご自身の PC 側、 : の後ろに指定したディレクトリをコンテナ側として認識し、それらを紐付けますという意味です。/appはコンテナ側のディレクトリです。このディレクトリと現在のディレクトリ (pwd) が紐付けられます。-pはポート番号を紐付けるよ、という意味です。9000:9000はご自身の PC 側とコンテナ側のポート番号の紐付け指定です。--nameはコンテナの名前を指定するよ、というオプションです。vue_appはコンテナの名前です。なんでも OK です。-itはインタラクティブモードで起動するよ、という意味です。 Dockerfile の最後に記述したシェルにつなぐということです。-dはコンテナをバックグラウンドで起動するよ、という意味です。デタッチの意味です。vue_app_imageはコンテナのもととなるイメージのタグ名です。ここでボリュームの紐付けについて触れておきます。
Docker コンテナはあくまでご自身の PC 上で動作する別の環境です。したがって、その環境内で操作したいファイルは通常、そのコンテナ内で作る必要があります。しかし、 Web アプリケーションを作るために書いたたくさんのHTMLやJavaScriptのファイルをコンテナ内に残しておくと、コンテナを誤って消してしまったときなどに枕を濡らすことになります。コンテナ側で GitHub にプッシュしてもいいですが、そういうファイルの管理はご自身の PC 側でやったほうがなにかと便利ですよね。そこで、手元の特定のディレクトリと、コンテナ内の特定のディレクトリを紐付け、ファイルのやり取りを簡単に行えるようにしましょう。出来上がったコンテナは次のコマンドで確認することができます。
$ docker ps -aDocker コンテナに入って作業を開始しよう
では早速用意した Docker コンテナを起動して接続し、作業を開始しましょう。
次のコマンドでこれが実現します。docker exec -it vue_app shだいたいこれまでと同じ感じですね。
dockerは Docker を使うz(ryexecはコンテナを実行するぜ、という意味-itはインタラクティブモードで起動するぜという意味vue_appは起動させるコンテナの名前shはコンテナのシェルを使うぜ、という意味これで、コンテナ側のシェルが操作できる状態になっていると思います。
lsコマンドなどで、さきほど紐付けたディレクトリに入って、ローカルと連携しているかどうか、適当なファイルを作って確かめてみてください。ここまでで、実はDockerの用意は完了です。
ここからはVue.jsを使ったサンプルを動かしてみようと思います。Vue-cli を使って Vue のプロジェクトを立てよう
Vue-cliとこれまで何も説明もなく登場させていました。すいません。これは、 cli (command line interface) のことで、 Vue に必要ないろいろなことを簡単にできるようにしてくれる親切なツールです。
https://cli.vuejs.org/ここでは vue-cli3 は使いません。 (特に理由はありません) cli3 を使いたい場合は vue-cli のインストールを
npm install -g @vue/cliとしてもらえば OK です。
ここでは Vue-cli で用意されているテンプレートから webpack を使ってみます。
作業ディレクトリ (/app) に移動し、以下のコマンドを入力します。/app:$ vue init webpack /app:$ npm installwebpack のプロジェクトを新規作成しますよ、 ということです。
これで webpack のテンプレートに入っている初期のファイルがザバーっと自動的に生成されると思います。この辺りの説明は省きます。次に、 config/index.js を編集します。これは、 vue-cli で HTTP アクセスさせるときに開放しているポートを使わないと、手元の PC からは見えないからです。
host: 'localhost', port: 8080,を
host: '0.0.0.0', port: 9000,に変更してください、 Dockerfile に指定して開放したポート番号です。また、 localhost も変更しています。これは、まずはこんなもんだと思っておいてください。
次に、 node 環境の実行です。
/app:$ npm run devこれですべて完了です。
http://localhost:9000 にアクセスして webpack が動いていることを確認してください。これで、Dockerのコマンドたちが何をしているのか、少しクリアになったかと思います。何かのお役に立てそうなら、ぜひストックを。今後も少しずつ内容はブラッシュアップします。
長々とお付き合いいただき、ありがとうございました。
- 投稿日:2019-12-19T05:07:01+09:00
MySQL8.0で全文検索(mecab)を試してみる。
この記事はディップ Advent Calendar 2019の19日目の記事です。
まえがき
DockerでMySQL8.0の全文検索機能をお試しする環境をつくってみます。
そもそも全文検索って何なのさ、というのは以下の記事がとても参考になります。
・検索エンジンはいかにして動くのか?なお、コンテナ作成後のSQLは、ホストからMySQL Workbenchで接続・実行しています。
※dockerコンテナの中からmysql clientで接続して、最後の全文検索用SQLを投げようとしたところ、日本語を入力した途端に文字が消えるという事象に遭遇し、断念。。構築手順
フォルダ構成. ├── docker │ └── mysql8.0-mecab │ ├── Dockerfile │ ├── conf.d │ │ └── my.cnf │ └── initdb.d │ └── init.sql ├── docker-compose.yml上のようなフォルダ構成で、下記のファイルを用意していきます。
docker-compose.yml
my.cnfはローカルからコンテナの/etc/mysql/conf.dにマウントさせてます。
また、/docker-entrypoint-initdb.dにマウントされたシェルスクリプトやSQLが初回起動時に実行されます。
今回はmecabプラグインのインストールや検証用テーブル作成用のSQLを配置しました(後述)。docker-compose.ymlversion: '3.3' services: mysql80-mecab: build: ./docker/mysql8.0-mecab container_name: mysql8.0-mecab environment: MYSQL_DATABASE: sample_db MYSQL_USER: jabe MYSQL_PASSWORD: jabe123 MYSQL_ROOT_PASSWORD: jabe123 TZ: 'Asia/Tokyo' ports: - "3306:3306" volumes: - ./docker/mysql8.0-mecab/conf.d:/etc/mysql/conf.d - ./docker/mysql8.0-mecab/initdb.d:/docker-entrypoint-initdb.dDockerfile
mecabのインストールをします。また、
echo "dicdir=/var/lib/mecab/dic/ipadic-utf8" > /etc/mecabrcの部分でmecabの単語辞書をIPA辞書に切り替えています。DockerfileFROM mysql:8.0 RUN apt-get update && apt-get install -y \ mecab \ libmecab-dev \ mecab-ipadic-utf8 \ locales \ && locale-gen ja_JP.UTF-8 \ && echo "dicdir=/var/lib/mecab/dic/ipadic-utf8" > /etc/mecabrc ENV LANG ja_JP.UTF-8 ENV LC_CTYPE ja_JP.UTF-8my.cnf
MySQLにmecabrc(mecabの設定ファイル。前述のDockerfileで単語辞書のパスを記載しました。)のパスを通します。
また、mecabがトークン解析をする際のトークンの分割単位を決めます。my.cnf[mysql] default-character-set=utf8mb4 [client] default-character-set=utf8mb4 [mysqld] # mecabrcファイルの格納先 loose-mecab-rc-file=/etc/mecabrc # mecabが解析時にトークン分割する際のトークンサイズを指定 innodb_ft_min_token_size=1 # デフォルト認証プラグインの設定 default-authentication-plugin = mysql_native_password collation-server=utf8mb4_unicode_ci character-set-server=utf8mb4 skip-character-set-client-handshake初期化用SQL
前述のコンテナ初回起動時に実行させるSQLです。ここでは以下をやっています。
- mecabプラグインのインストール
- テーブル作成&初期データ投入
特に、
fulltext (street_address) with parser mecabで全文検索用のindexを作成します。init.sqluse sample_db; /*** 1. mecabプラグインのインストール ***/ install plugin mecab soname 'libpluginmecab.so'; /*** 2. テーブル初期化 ***/ drop table if exists employee; create table employee ( id int unsigned auto_increment not null primary key , name varchar(40) , street_address varchar(90) , fulltext (street_address) with parser mecab ) engine=innodb character set utf8mb4; insert into employee (id, name, street_address) values (1, "太郎","東京都新宿区"); insert into employee (id, name, street_address) values (2, "次郎","京都府京都市北区"); insert into employee (id, name, street_address) values (3, "三郎","愛媛県松山市"); insert into employee (id, name, street_address) values (4, "四郎","香川県高松市"); insert into employee (id, name, street_address) values (5, "五郎","徳島県徳島市"); insert into employee (id, name, street_address) values (6, "花子","高知県高知市");コンテナ起動&確認
docker-composeコマンドでコンテナの起動、確認します。
# 起動 $ docker-compose up -d # 起動確認 $ docker-compose ps # ログチェック $ docker-compose logsDB確認
コンテナ起動後、MySQLにログインし、以下が確認できればOKです!
- mecabプラグインがあること。
- テーブル作成&初期データ登録ができてること。
MySQLの状態確認。Execute: > show create table employee + ---------- + ----------------- + | Table | Create Table | + ---------- + ----------------- + | employee | CREATE TABLE `employee` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(40) DEFAULT NULL, `street_address` varchar(90) DEFAULT NULL, PRIMARY KEY (`id`), FULLTEXT KEY `street_address` (`street_address`) /*!50100 WITH PARSER `mecab` */ ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci | + ---------- + ----------------- + 1 rows Execute: > select * from employee + ------- + --------- + ------------------- + | id | name | street_address | + ------- + --------- + ------------------- + | 1 | 太郎 | 東京都新宿区 | | 2 | 次郎 | 京都府京都市北区 | | 3 | 三郎 | 愛媛県松山市 | | 4 | 四郎 | 香川県高松市 | | 5 | 五郎 | 徳島県徳島市 | | 6 | 花子 | 高知県高知市 | + ------- + --------- + ------------------- + 7 rowsいざ、全文検索。
「京都」を検索して「東京都」がでなければ、できあがり。
Execute: > select * from employee where match (street_address) against ('京都' in natural language mode) + ------- + --------- + ------------------- + | id | name | street_address | + ------- + --------- + ------------------- + | 2 | 次郎 | 京都府京都市北区 | + ------- + --------- + ------------------- + 2 rowsあとがき
最後までお付き合い頂きありがとうございました。
不備、おかしなところあれば、ご指摘頂けますと幸いです。
また、まえがきで遭遇した事象について有力情報お待ちしておりますm(_ _)m参考記事
以下を参考にさせていただきました。感謝です。
https://dev.mysql.com/doc/refman/8.0/en/fulltext-search-mecab.html
https://qiita.com/clustfe/items/3f5160ce77c5db9c7b30
https://qiita.com/ucan-lab/items/b094dbfc12ac1cbee8cb
https://qiita.com/motoki_giants/items/0c3b9d174edef9410310
https://qiita.com/furu8ma/items/75e5b1df29fef04ec7f1
- 投稿日:2019-12-19T03:14:04+09:00
AWS入門、ついでにDocker入門
目次
1.概要
2.Dockerとは
3.動かしてみよう
4.管理してみよう
1.概要
・AWS/Docker初心者が
AWSを使ってDockerを動かしてみました。・AWSを使って様々な製品、技術に触れるハードルが下がればと思います。
2.Dockerとは
コンテナ型の仮想化環境を
作成、配布、実行するためのプラットフォームホストOS上で仮想化するので
○起動が高速、環境構築が簡単・・・
△ホストOSと同一のOSしか使えない・・・
Dockerの起動イメージ
3.Dockerを動かしてみよう
(1)AWS EC2の立ち上げ
(2)Dockerをインストール
(3)DockerイメージからDockerコンテナを動かす(1)AWS EC2の立ち上げ
EC2コンソール上からインスタンスを立ち上げる。
(今回はAmazon Linux 2)(2)Dockerをインストール
AWS提供リポジトリからDockerが取得できる。
(数秒で完了)docker1.log$ sudo yum install docker 読み込んだプラグイン:extras_suggestions, langpacks, priorities, update-motd ~中略~ インストール:docker.x86_64 0:18.09.9ce-2.amzn2 依存性関連をインストールしました: containerd.x86_64 0:1.2.6-1.amzn2 libcgroup.x86_64 0:0.41-21.amzn2 pigz.x86_64 0:2.3.4-1.amzn2.0.1 runc.x86_64 0:1.0.0-0.1.20190510.git2b18fe1.amzn2 完了しました!(3)DockerイメージからDockerコンテナを動かしてみる
「Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world」
→ローカルにhello-worldイメージが存在しないため、
DockerHubのライブラリから取得。docker2.log$sudo docker run hello-world Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world 1b930d010525: Pull complete Digest: sha256:4fe721ccc2e8dc7362278a29dc660d833570ec2682f4e4194f4ee23e415e1064 Status: Downloaded newer image for hello-world:latest Hello from Docker! This message shows that your installation appears to be working correctly.
4.Dockerを管理してみよう
(1)DockerHub
(2)Amazon ECS/ECR(1)DockerHub
Dockerイメージを公開・共有できるサービス
(2)Amazon ECS/ECR
ECS:Amazon Elastic Container Service
Dockerコンテナの管理サービス。
- 投稿日:2019-12-19T01:41:32+09:00
DockerのMaxscaleでホストにマウントしたログをログローテーション (2)
cronのDockerコンテナからcronを動かして別のDockerコンテナのlogroate実行
動作確認環境
AWS Workspaces
Amazon Linux2 (Time zone: Asia/Tokyo (JST, +0900))
Maxscale 2.4.4ディレクトリ
home/username/logrotate |--log | |--maxscale | | |--maxscale.log |--maxscale | |--maxscale_logrotate |--maxscale-dockerfiles | |--Dockerfile |--cron-logrotate-docker-dockerfiles | |--Dockerfile | |--maxscale-cronFROM mariadb/maxscale:2.4.4 RUN apt-get update && apt-get -y install logrotate #RUN mv /etc/cron.daily/logrotate /etc/cron.hourly/logrotate #ADD maxscale-cron /etc/cron.d/maxscale-cron #RUN chmod 0644 /etc/cron.d/maxscale-cronmaxscale/maxscale_logrotate/var/log/maxscale/maxscale.log { su maxscale maxscale create 644 maxscale maxscale rotate 3 missingok compress delaycompress sharedscripts size 1K dateext dateformat %Y%m%d%H%M%S postrotate kill -USR1 `cat /var/run/maxscale/maxscale.pid` endscript }cron-logrotate-docker-dockerfiles/DockerfileFROM alpine:3.10.3 RUN apk --update add docker && rm -rf /var/cache/apk/* COPY maxscale-cron /etc/crontabs/root # cronのdaemonを起動(log level=1, foreground) CMD crond -l 1 -fcron-logrotate-docker-dockerfiles/maxscale-cron*/1 * * * * docker exec maxscale /usr/sbin/logrotate -f /etc/logrotate.d/maxscale_logrotate >> /var/log/cron.log 2>&1Dockerイメージ作成
$ mkdir -p log/maxscale $ chmod 777 log/maxscale $ mkdir maxscale $ mkdir maxscale-dockerfiles $ mkdir cron-logrotate-docker-dockerfiles $ cd maxscale-dockerfiles $ docker build -t maxscale-log:2.4.4 . $ cd .. $ cd cron-logrotate-docker-dockerfiles $ docker build -t base:1.0 .動作確認
$ cd .. $ sudo chown root:root maxscale/maxscale_logrotate $ docker run -d \ --name base \ -v /var/run/docker.sock:/var/run/docker.sock \ base:1.0 # MaxscaleのDockerコンテナ起動 $ docker run \ -d \ --name maxscale \ -v $(pwd)/log/maxscale:/var/log/maxscale \ -v $(pwd)/maxscale/maxscale_logrotate:/etc/logrotate.d/maxscale_logrotate \ maxscale-log:2.4.4 \ maxscale -d -U maxscale -l file # ログ確認 $ ls -l log/maxscale/ 合計 8 -rw-r--r-- 1 chrony ssh_keys 0 12月 19 01:40 maxscale.log -rw-r--r-- 1 chrony ssh_keys 707 12月 19 01:39 maxscale.log20191218163900.gz -rw-r--r-- 1 chrony ssh_keys 187 12月 19 01:40 maxscale.log20191218164000
- 投稿日:2019-12-19T01:11:38+09:00
お手軽防犯システム「Ban-Ken Johnny」を作ってみた?
MAN WITH A MISSION
頭はオオカミ、体は人間の究極の生命体。
彼らは自分たちの音楽で世界征服を目指す、最高にアツい集団だ。そんな「MAN WITH A MISSION」のGt,Vo,Rap ジャン・ケン・ジョニー(Jean-Ken Johnny)と番犬をかけあわせた、というのが「Ban-Ken Johnny(番犬ジョニー)」の由来である。
オオカミと番犬、イヌ科の奇跡のコラボレーション!
センスしかないですね(笑)
ファンクラブ会員限定の10周年記念ツアー当たって欲しいなぁ...はい、前置きはこれぐらいにして「Ban-Ken Johnny」の機能を紹介します。
「Ban-Ken Johnny」の機能
- 人感センサーで人の気配を感知したら、スマホにアラートメッセージを送る
- 自分が家にいる間はセンサーが反応して欲しくないので、監視機能の
ON/OFFを切り替えできる。- 毎回家出る時にon/offするのはメンドイので、家の外からオンラインでアラート通知を
ON/OFFできる「Ban-Ken Johnny」にできることはざっとこれぐらいです。
イメージがつきやすいように「Ban-ken Johnny」のデモをしました。1.監視機能をON
監視機能はOFFになっているので、startボタンを押してONにします。
ONになりました。2.家に誰か侵入(ラズパイの人感センサーに反応)
監視機能がONの状態で、
家に設置されているラズペリーパイの前を誰かが横切ります(なぜか物悲しい写真ですね...笑)そうすると、
自分のスマホに通知が飛んできました!
まあこんな感じです笑
デモでイメージを掴んでいただいたところで、「Ban-Ken Johnny」の仕組みを紹介します。「Ban-Ken Johnny」の概要
図だけ見てもよくわからないと思うので、ここからは仕組みを少しだけ詳しく説明して行こうと思います。
興味ないよーという方は編集後記まで読み飛ばしてください1.Mattermost
Mattermostは自分が侵入者検知メッセージを受け取るために使用します。
別にSlackでも良かったのですが、勉強のためにも自分でチャット環境を用意してみることにしました。
今回MattermostはEC2上でdockerを使って動かします。
個人利用なので、preview版を使うことにしました。
mattermost/mattermost-preview
preview版は一つのコンテナ内に、mattermostアプリとmysqlが動作していて、コンテナ一つを動かすだけでmattermostを使用できます。加えてmattermostの前段にnginxも置いてみることにしました。(理由はなんとなくカッコイイから)
Mattermostは親切なので、Mattermost用のnginx.confを用意してくれています。
これをありがたく使わせてもらいます。それらを踏まえると、mattermostを動かすためのdocker-compose.ymlはこんな感じになります。
docker-compose.ymlversion: "3" services: nginx: image: nginx:1.17 container_name: nginx volumes: - "./etc/nginx:/etc/nginx" - "./var/log/nginx:/var/log/nginx" ports: - 8080:80 links: - mattermost mattermost: image: mattermost/mattermost-preview container_name: mattermost volumes: - "./mysql:/var/lib/mysql"ディレクトリ構成はこんな感じです。
./mattermost ├── ./docker-compose.yml ├── ./etc │ └── ./etc/nginx │ └── ./etc/nginx/nginx.conf ├── ./mysql └── ./var └── ./var/log └── ./var/log/nginx今回はEC2で動かして、その前段にELBとRoute53を置きます(ELB置くならnginxいるのか?というツッコミはなしで)
Route53で設定したドメイン名(ban-ken-johnny.example.comとします)にアクセスしてみます
はい、無事表示されました。
(よくわからないところで凝り性を発揮してしまい、https対応のためにAWS Certificate Manager使って証明書発行したり、ALBでHTTPtoHTTPS対応したりしたんですが、長くなるのでまたの機会に書けたらなぁと...)とりあえずアカウントを作成してログインします。
ログインしてやったこととしては、「Ban-Ken Johnny」がアラートメッセージを送って来れるように、Incominng Webhookの設定と、プッシュ通知サーバーの設定をしました。
ただ自前でpush通知用サーバーを用意するほど余裕がなかったので、Mattermostが用意してくれているテスト確認用のサーバーを使うことにしました。
あんまり通知飛ばさないと思うのでMattermostさんご容赦を...さて、もろもろを終えると「Ban-Ken Johnny」からWebhook経由でメッセージを送り、スマホに通知がくるということができるようになります。
2. Flask App
オンラインからをアラート通知を
on/offにするために、アラートの状態を管理してくれるアプリをFlaskで実装しました。
本当に簡単なアプリで、機能としては
/startや/stopのGETリクエストがきたら、DBのstatusカラムの値を変更するという本当にただそれだけのアプリです。
このアプリもdockerを使ってEC2上で動かします。docker-compose.ymlversion: "3" services: nginx: image: nginx:1.17 container_name: nginx_flask volumes: - "./etc/nginx:/etc/nginx" ports: - 8081:80 links: - flask-app flask-app: build: ../ image: flask-app container_name: flask-app environment: - DB_USER=root - DB_PASSWORD=setting_password - DB_HOST=mysql_flask - DB_NAME=flaskdb links: - mysql mysql: container_name: mysql_flask image: mysql:5.7 environment: - MYSQL_ROOT_PASSWORD=setting_password - MYSQL_DATABASE=flaskdb volumes: - ./sql:/docker-entrypoint-initdb.d command: "mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci"ディレクトリ構成はこんな感じです。
./flask-app ├── ./Dockerfile ├── ./config │ └── ./config/config.py ├── ./definitions │ ├── ./definitions/__init__.py │ └── ./definitions/database.py ├── ./docker │ ├── ./docker/docker-compose.yml │ ├── ./docker/etc │ │ └── ./docker/etc/nginx │ │ └── ./docker/etc/nginx/nginx.conf │ └── ./docker/sql │ └── ./docker/sql/init_ddl.sql ├── ./models │ ├── ./models/__init__.py │ ├── ./models/alert_status.py │ └── ./models/dao │ ├── ./models/dao/__init__.py │ └── ./models/dao/alert_status.py ├── ./requirements.txt └── ./server.pyこれにより、アラートの状態を管理してくれる簡単なAPIが完成しました。
これぐらいなら
Amazon API Gateway → AWS lambda → Amazon DynamoDBの完全サーバレス構成にできそうなので、時間ができたらサーバレス構成に変更して見たいと思います。3. S3(Front End)
スマホからオンラインでアラートの
ON/OFFを命令するためのフロントエンドは、Amazon S3 での静的ウェブサイトのホスティングを使って動かすことにしました。
正直フロント技術はほとんど触ってきていないところで、かつデザインのセンスもないのでパパッと手軽に実装して、S3にデプロイしちゃいました。
本当はVue.jsとか使いたいし、CSSも初心者感を無くしたいし...
そんなのは夢のまた夢で、イケてない見た目になっちゃいました...
ごめんねジョニー...4. RaspberryPi
さあ最後に、ラズパイを触っていきます。
「Ban-Ken Johnny」を作るために、今回初めてラズパイを購入しました。
今年一年頑張った自分へのクリスマスプレゼントですねラズパイには、「人感センサーをつけて、人の気配を検知したらMattermostにアラート通知する」という、根幹の部分を担ってもらいます。
このプロセスは常時動きながら家を監視しておいて欲しいので、systemdを使ってデーモンプロセスとして動かすことにしました。プロセスとして動かすpythonのスクリプトはこんな感じ。
ban-ken-johnny.py#!/usr/bin/python3 import requests import json from time import sleep from datetime import datetime import dateutil.tz as tz import sys import RPi.GPIO as GPIO GPIO_PIN = 18 GPIO.setmode(GPIO.BCM) GPIO.setup(GPIO_PIN, GPIO.IN) STOPPED_STATUS = 2 WEBHOOK_URL = 'https://ban-ken-johnny.example.com/hooks/abcdefghijklmnopqrstuvwxyz' def is_alert_stopped(): response = requests.get("https://ban-ken-johnny.example.com:8080/getAlertStatus") content = json.loads(str.strip(response.content.decode("utf-8"))) if int(content['status']) == STOPPED_STATUS: return True return False def post_alert(): headers = {'content-type': 'application/json; charset=UTF-8'} now = datetime.today().astimezone(tz.gettz('Asia/Tokyo')).strftime('%Y/%m/%d %H:%M') payload = { "text": "侵入者ヲ検知シマシタ!:wolf:", "channel": "town-square", "attachments": [ { "text": "**Time:** "+now, "mrkdwn_in": ["text"] } ] } response = requests.post(WEBHOOK_URL, data=json.dumps(payload), headers=headers) res = { "status" : str(response.status_code), "mesage" : response.content.decode("utf-8") } return json.dumps(res) if __name__ == "__main__": try: while True: if GPIO.input(GPIO_PIN) == GPIO.HIGH: if is_alert_stopped() == False: post_alert() sleep(10) except Exception as err: print(str(err)) sys.exit(1) finally: GPIO.cleanup()このpythonプロセスを
systemdを使ってデーモンプロセスとして登録するために、ban-ken-johnny.serviceファイルを用意します。ban-ken-johnny.service[Unit] Description=Ban-Ken Johnny Requires=network.target [Service] Type=simple ExecStart=/opt/ban_ken_johnny.py Restart=always [Install] WantedBy=multi-user.targetこの
ban-ken-johnny.serviceを/etc/systemd/system直下に置き、ban-ken-johnny.pyは、serviceファイルのExecStartで指定しているように、/opt直下に置きます。
準備ができたらコマンドを実行して、ban-ken-johnny.serviceを起動します#rootにpython-dateutilをインストール $ sudo pip3 install python-dateutil $ sudo systemctl daemon-reload $ sudo systemctl start ban-ken-johnny.service #OSが起動したらプロセスも自動起動する様にする $ sudo systemctl enable ban-ken-johnny.serviceプロセスのステータスを確認してみます。
$ sudo systemctl status ban-ken-johnny.service ● ban-ken-johnny.service - Ban-Ken Johnny Loaded: loaded (/etc/systemd/system/ban-ken-johnny.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2019-12-12 21:20:20 JST; 8s ago Main PID: 3010 (ban_ken_johnny.) Tasks: 1 (limit: 2200) Memory: 11.7M CGroup: /system.slice/ban-ken-johnny.service └─3010 /usr/bin/python3 /opt/ban_ken_johnny.py 12月 12 21:20:20 raspberrypi systemd[1]: Started Ban-Ken Johnny.ちゃんと動いてますね?
あとは人感センサーが反応したら、ちゃんと通知がくるか確認するだけです!無事動作しました!!
ちゃんとON/OFFにしたがって、通知を飛ばしてきてくれます!!
ヤッタゼ!!これで「Ban-Ken Johnny」は完成です。
お手軽と言いながら、地味に時間かかっちゃいました...
これで家の留守中も安心です?編集後記
完成して使い始めたは良いものの、なぜか2分置きに
GPIOからinputを検知してしまうという不具合が発生しました。
そのため2分置きに「侵入者ヲ検知シマシタ!?」と送信してきます。
鬼メッセージ送信機へと成り下がってしまったジョニーをどうにかして直したいのですが、ラズパイ初心者の私にはお手上げ状態です...
アドベントカレンダーの締め切りもあったので、すぐに届くセンサーをAmazonで選んで購入したのですが、そのセンサーが悪かったのかもしれません...
今見たら誰も評価してないし...一応GitHubにも公開しているので、参考までに...
トリアエズ有識者ノ皆サマ、是非オ助ケヲ!!
- 投稿日:2019-12-19T00:25:07+09:00
Python3系のAWS CLIと.NET Core v2.1の入ったCentOSイメージを作る
背景
仕事で.NET Coreのソフトをコンテナ化する機会があったので、そのまとめとPython2系が2020年1月1日に廃止されるので、Python3系の導入についても触れていこうと思います。
二番煎じかもしれませんが、ご了承ください。
内容
以下の構成でDockerのイメージを作成します。
- baseImage : CentOS
- Python 3系
- .NET Core v2.1
導入
(1) DockerfileをClone
まず、以下のリポジトリをクローンしてください。
# ファイルをClone $ git clone https://github.com/susu-to-susu/Dockerfile_aws_dotnet.git(2)イメージの作成
Dockerfileの場所まで移動して、buildしてイメージを作成してください。
# ディレクトリ移動 $ cd Dockerfile_windows_dotnet # イメージの作成 $ docker build -t dotnet_aws .(3)コンテナの作成
以下のコマンドでコンテナを作成します。
# コンテナの作成 $ docker run --name dotnet_aws -itd dotnet_aws bash(4)動作確認
以下のコマンドでコンテナにログインをしてaws-cliとdotnetCoreの確認をします。
# アタッチ(ログイン) $ docker attach dotnet_aws [root@eb395ae3adad /]# dotnet --version 2.1.509 [root@eb395ae3adad /]# aws --version aws-cli/1.16.305 Python/3.6.8 Linux/4.9.184-linuxkit botocore/1.13.41解説
Dockerfileの中身は以下のようになっています。
# Sample Dockerfile # Indicates that the centos image will be used as the base image. FROM centos:latest # Install Python RUN yum update -y RUN yum upgrade -y RUN yum install -y wget RUN yum install -y python3 # AWS CLI Settings RUN wget https://bootstrap.pypa.io/get-pip.py RUN python3 get-pip.py # Install awscli # RUN pip install awscli RUN pip3 install awscli --upgrade --user ENV PATH $PATH:/root/.local/bin # Metadata indicating an image maintainer. LABEL maintainer="susu-susu@github.com" # dotnet Core v2.1 RUN yum install -y dotnet-sdk-2.1やっていることは非常に簡単で、python3とdotnetCore v2.1をyumでインストールしています。
ENV PATH $PATH:/root/.local/binここで気を付けることは、pip3でaws-cliをインストールした場合、デフォルトでは
/root/.local/binにコマンドが格納されるのですが、環境変数に$PATHが適応されてません。少なくとも自分がやった時はそうでした。そのため、ENVに書く必要があります。
ターゲットとしては、dotnetCoreをWindows以外で利用したい。コンテナ化して使いたいって場合に最適です。
何か誤字脱字ありましたら、ご指摘頂けると幸いです。
参考リンク







































