- 投稿日:2020-07-13T22:16:20+09:00
Slack AppHomeでAWS環境構築モーダル作ってみた
Slack AppHomeは、アプリホーム画面を作れて便利ですね。
今回はAWS環境を構築する機能を作ってみました。
実装時のポイントなど書いていきます!これからAppHome使う方の参考になれば幸いです!なぜ作ったのか
私の現場ではEC2を使って複数のプロジェクト環境を作ることがあります。ただ、今まではAWSコンソールからEC2/CloudWatchなどを設定する運用になってました。
環境構築手順は、CloudFormationでテンプレート化できますが、それでもAWSコンソールログインなど手間ですね。そこで、みんな慣れているSlackから環境作れるようにしました。完成イメージ
AppHomeのボタンを押すと、モーダルが表示する仕組みにしました。
モーダルへの入力は、操作を簡略化したかったのでAMI選択程度にしました。
そして、処理開始と終了の連絡を特定のチャンネルに飛ばすようにしました。
(上のgifはデモ用なので、ami名やEIPなどは固定ですが、本物はami名/EIP取得して表示してます)構成
AWS Lambda(nodejs)で処理する形にしました。
今回のケースでは、4回イベントを処理するタイミングがあります。
それぞれの処理内容を説明します。1.AppHome画面表示
AppHomeへの内容表示は、
SlackAPI(views.publish)
で行います。
一度送れば何度でも表示できます。ただ、表示内容を更新したい場合もあると思うので、AppHome表示時のapp_home_opened
イベントをSubscribeして、毎回Publishして良いと思います。(subscribeには、自身のSlackアプリメニューのevent subscriptionsより購読設定ください。参考:Using the Slack Events API)
以下のtypeでイベント内容を判別できます。{ "body":{ "event":{ "type":"app_home_opened" } } }
views.publish
は以下のようなイメージです。const home = { "type":"home", "blocks": [{ "type": "section", "text": { "type": "mrkdwn", "text": "*Welcome!!* \nDo you want to create EC2?????" }, "accessory": { "type": "button", "action_id": "固有のaction_ID", "text": { "type": "plain_text", "text": "createEC2" } } }] } const args = { 'user_id': "SlackのユーザID", 'view': JSON.stringify(home) 'token': "slackアプリ登録時のbot token" } await viewsPublish(args)SlackのユーザIDは、SlackAPI
users.info
を使えば、ユーザ名から取得できます。
参考:users.info
action_id
については後述します。2.ボタン押下(AppHome)
ボタンはInteractiveComponentなので、まずは
InteractiveComponent
にRequestURLの登録が必要です。(https://api.slack.com/interactivity/handling)
Interactivityから送られるPayloadにはtrigger_id
があります。これを使うことで操作元に反応を返すことができます。なおtrigger_id
の有効時間は3秒です。3秒以内に返さないと反応してくれません。
以下のようにモーダル内容とtrigger_idをviews.open
に渡すとモーダル表示できます。参考:views.openconst modal = { "type": "modal", "title": { "type": "plain_text", "text": "CreateEC2" }, "blocks": [ { "type": "input", "block_id": "固有のBlockID", "element": { "type": "static_select", "action_id": "固有のActionID", "placeholder": { "type": "plain_text", "text": "Select a item", "emoji": true }, "options":[ /// ] }, }, /// ], "close": { "type": "plain_text", "text": "Cancel" }, "submit": { "type": "plain_text", "text": "Save", }, } const args = { 'trigger_id': "受け取ったtrigger_id", 'view': JSON.stringify(modal) 'token': "slackアプリ登録時のbot token" } await viewsOpen(args)ここでポイントは、
block_id
とaction_id
にそれぞれ一意な値を設定することです。
このあとモーダルから入力値を抽出するときにこの2つが必要となります。3.モーダルOK押下(AppHome)
モーダルOKを押すと、typeが
view_submission
のPayloadが送られてきます。
また、block_id
、action_id
の名称からモーダルの入力項目を取り出せます。
Payload中では以下のように入力値が格納されています。{ "view":{ "state":{ "values":{ "設定したblock_id":{ "設定したaction_id":{ "value": "入力値" // テキスト入力の場合 } }, "設定したblock_id":{ "設定したaction_id":{ "selected_option":{ "value": "選択値" // リスト選択の場合 } } }, } } } }3-1.スタック作成
AWS-SDKからCloudFormation(createStack)をコールします。
このとき、createStack
のNotificationARNs
パラメータにSNSトピックARNを設定すると、スタック作成のイベント受け取れます。
スタック作成開始時と終了時に時間差でSlackチャンネル通知してあげると、裏でBotが頑張ってた感があって好きです^^
snsから来るイベントは以下のような感じです。{ "Records": [ { "EventSource": "aws:sns", "EventVersion": "1.0", "EventSubscriptionArn": "arn:XXXXX", "Sns": { "Type": "Notification", "MessageId": "XXXXX", "TopicArn": "arn:XXXXX", "Subject": "AWS CloudFormation Notification", "Message": "StackId=XXXXXX", "Timestamp": "2020-XX-XXT02:50:11.963Z", "SignatureVersion": "1", "Signature": "XXXXXX", "SigningCertUrl": "XXXX", "UnsubscribeUrl": "XXXX", "MessageAttributes": {} } } ] }その通知が処理中なのか、完了なのかは
Message
内容から判別しました。
上記は割愛してますが、メッセージ内には様々な情報が記載されています。このメッセージをパースすることで情報を取り出せます。(他にいい方法あれば教えて欲しいです・・私はsns初めてだったのでこれしか思いつきませんでした・・)3-2.モーダルクローズ
モーダルを使う際は画面クローズも考慮必要です。
OKボタンを押しても画面クローズを明示的に指定しないとモーダルは閉じません。
ステータス200
でresponse{"response_action": "clear"}
を返せば、モーダルが閉じてくれます。
参考:Closing views
Chancelボタンと×ボタンはResponseなしでも閉じてくれます。
これらの操作イベントを受けたい場合は、モーダル作成時にnotify_on_close:true
を指定するとview_closed
イベントを受け取れます。4.スタック作成完了
前述したスタック作成完了の通知ですね。
SNS通知内にはStackNameがあるので、AWS-SDKのdescribeStacks
やdescribeStackResources
でリソース詳細などを取得できます。
Slackへ通知メッセージは、BlockKitBuilderでいい感じのメッセージを作ってあげるといいですね。テンプレートも用意されているので、参考になります。おわりに
SlackAppHomeを使ってAWS環境構築を試してみました。
AppHomeなどを使ってみて、ChatOpsを実現すれば運用負荷が減り、チームが本業に集中できますね。あとAppHomeは、Slackのスマホアプリからも使えるのがいいですね!
SlackAPIがボタンやモーダルなど使いやすいコンポーネントを用意してくれている+スマホ版表示はやってくれるので、スマホ対応方法を考えなくてよいです^^
これで、電車で移動中にポチポチで環境構築できます^^実装方法がわかれば簡単なので、ぜひいろいろ作ってみてください^^
- 投稿日:2020-07-13T19:54:05+09:00
AWS SDK のSSL証明書エラーが出た場合【Windows10】
- よくある、実行環境にSSL証明書がない場合に発生するエラー
cURL error 60: SSL certificate problem: unable to get local issuer certificate (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) in xxxcURL error 77: error setting certificate verify locations: CAfile: xxx CApath: none (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) in xxx on line 195
- 解決策
cURLサイトから証明書をダウンロード出来るらしい
https://curl.haxx.se/docs/caextract.html
サイト内の cacert.pem というリンクからダウンロード出来る
ダウンロードしたら適当な場所に配置して、php.iniの設定
openssl.cafile='C:\tools\php\extras\ssl\cacert.pem'apacheとかnginxならサービスを再起動
これで完了参考: https://docs.aws.amazon.com/ja_jp/sdk-for-php/v3/developer-guide/faq.html
- 投稿日:2020-07-13T15:33:47+09:00
AWS初心者向け用語集①
業務でAWSを使うことになったので、お勉強中です。
AWS初心者が戸惑いがちな用語を、備忘録も兼ねて、なるべくかみ砕いた言葉で
まとめておきたいと思います。EC2
・Amazon Elastic Compute Cloud (Amazon EC2) の略。
・Elasticとは、弾力のある、伸縮自在の、という意味。
・Amazonが提供している仮想サーバー構築サービス。
・簡単に言うと、Amazonが提供する、伸縮自在のクラウドサーバ。
・LinuxなどのOSを載せた仮想サーバーが作れる。
・EC2は稼働中(Running)のみ課金され、止まっているときは課金されない。
・使うときは必要なCPU/メモリなどのスペックを選んでインスタンスを作成する。※ちなみに「EC」と付いているが、「ECサイト」とは関係ない。
リージョン、アベイラビリティーゾーン(AZ)
リージョン > アベイラビリティゾーン
・日本には東京リージョンと大阪リージョンがある。
・サービス提供はリージョン単位。
・アベイラビリティゾーンは物理的に近距離に設置されたデータセンターの集まり。
・東京リージョンには4つのアベイラビリティゾーンがあり、データセンターは8箇所あるらしい。
・物理的に近い場所を選ぶことで、レスポンスタイムを短くすることができる。
・基本的に日本の会社は東京リージョンを選択する。災害対策として大阪を選ぶことも多い(マルチAZ)。AMI
・Amazon Machine Imageの略。
・ソフトウェア構成 (オペレーティングシステム、アプリケーションサーバー、アプリケーションなど) を記録したテンプレート。
・要は、OSのテンプレート。
・アカウント間でAMIを共有したり、同じAMIを使って複数のインスタンスを作成したりできる。
・AWSマーケットプレイスで第三者が作ったAMIを購入することもできる(販売もできる!)。IAM
・Amazon Identify and Access Managementの略。
・AWSの認証・認可サービス。
・IAMユーザー = IAM上で作成したユーザー。IAM管理者によってユーザーごとに権限設定が可能。※AMIとIAMは名前がややこしいけど全然意味が違うので注意!
VPC(Virtual Private Cloud)
(参考にした本)
・この1冊で合格! AWS認定ソリューションアーキテクト - アソシエイト テキスト&問題集↑Amazon unlimitedで無料で読めました!
- 投稿日:2020-07-13T14:04:21+09:00
Kubernetes入門 〜ローカル環境で触ってからEKSへのデプロイまで〜
この記事について
「Kubernetesを実際に触って勉強してみたい!」となって参考記事を探してみると、多くの記事がいきなりEKSやGKEといったクラウド上の本番環境を触るところからのスタートになっています。
「いきなり本番環境はちょっと……」「まずはローカル環境で軽く触って慣れてからクラウド上の環境を構築したい!」という方向けに、
- Kubernetesのアーキテクチャの勉強
- ローカルで実際に触ってみる
- EKSにデプロイ
という流れで、Kubernetesってこんな感じなんだ!という雰囲気を紹介したいと思います。
使用する環境・バージョン
- OS : macOS Mojave 10.14.5
- Docker.app : 2.2.0.5
- Kubernetes : v1.15.5
- eksctl : 0.23.0
- aws-cli : 2.0.10
前提条件
Docker App, AWS CLIはインストール済みの状態からスタートします。
読者に求める前提知識
- コンテナをある程度扱えること
- コンテナオーケストレーションという概念について知っていること
- VPC, セキュリティグループといったAWSの用語がある程度わかること
- (ECSの知識があると所々の例え話がわかりやすくなりますが、必須ではありません)
Kubernetesのアーキテクチャ
まず、Kubernetesの構成要素について詳しく説明します。
画像出典:Step by Step Introduction to Basic Concept of Kubernetes
参考:順を追って学ぶKubernetesのキホン〜ローカル環境でKubernetesクラスターを作成してKubernetesの概念を理解する〜Master
コンテナの起動・削除・カナリアデプロイといった、Kubernetesができるコンテナ管理・制御機能を担う頭脳部分です。
Masterを構成する主な要素は4つです。
- API Server
- etcd
- Scheduler
- Controller Manager
API Server
Kubernetesが扱うリソース(コンテナやボリュームなど)を操作するためのAPIがここで公開されています。
開発者(Devops)は、ターミナルでkubectl
コマンドを使うことでこのAPIを叩き、リソースの作成・削除・制御を行います。etcd
分散KVS(キーバリューストア)です。作成されたクラスター(コンテナを動かすサーバー群)の設定情報がここに保存されます。
Scheduler
コンテナの適切な配置場所を決定する機能を持ちます。
この機能があるがゆえに、「開発者は円滑な運用のために、どこのサーバーにコンテナを作成すべきか?」という設定を手動で行う必要がなくなり、アプリ側の開発に集中することができます。Controller Manager
Kubernetesが扱うリソースの制御を行います。
例えば、「起動コンテナの数を保つ」「サーバーダウン時の通知・対応を行う」「PodとServiceの紐付け」などを行います。参考:Kubernetes公式ドキュメント Kubernetesのコンポーネント
Cluster(クラスター)
コンテナを動かすサーバー群のことをKubernetesではクラスターと呼びます。
AWSのECSにおけるクラスターとほぼ同義です。Node(ノード)
コンテナを動かすサーバー1つ1つのことをKubernetesではノードと呼びます。
クラスターとは「1つのクラスターの中に、任意の数のノードが含まれる」という関係になっています。
上記のMasterに管理される対象であることから、「Slave Node」と呼ばれることもあります。ECSにおける、クラスター内のEC2インスタンスとほぼ同義です。
ローカルでKubernetesを動かす場合では、そのPCそのものが1つのノードという扱いになります。ノードの中に作成されるリソースは主に4つです。
- Pod
- Kubelet
- Container Engine
- Kube Proxy
Pod
ノード上で動かすコンテナ(組)のことです。
Podを構成するコンテナは複数個でもOKです。例えば、「nginxのコンテナとアプリコンテナの2つをセットにして1つのPodにする」ということができます(ECSでのタスクと同様です)。Kubelet
Masterからのリソース・スケジュール管理を受け付けるためのエージェントです。
ECSにおけるECS Container Agentとほぼ同義です。Container Engine
Dockerといった、コンテナの作成・削除等の処理を実際に実行するエンジンです。
Kube Proxy
ノードが受け付けたユーザーからのリクエストを、適切なPodに割り当て転送するネットワークプロキシです。
参考:Kubernetes公式ドキュメント Kubernetesのコンポーネント
始める前の初期状態
Kubernetesを使っていない状態でも、MasterにあるAPIを叩くための
kubectl
コマンドは存在します。Docker Appインストール時にkubectl
コマンドも同時にインストールされているからです。# このように、kubectlコマンドの存在がwhichコマンドで確認可能 $ which kubectl /usr/local/bin/kubectlしかし、コマンドのバージョン確認を行うと、以下のような表示になります。
$ kubectl version Client Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.5", GitCommit:"20c265fef0741dd71a66480e35bd69f18351daea", GitTreeState:"clean", BuildDate:"2019-10-15T19:16:51Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"darwin/amd64"} Unable to connect to the server: EOFこれは、「開発者クライアントの準備(=
kubectl
コマンド)は存在するが、それを受け付けるMasterのAPI Serverに接続できない(まだ存在しない)」という状態だということです。このままではKubernetesを利用できません。そのため、次にKuberbetesを有効化して、ローカルにKubernetes Serverを立ち上げる操作を行います。
ローカルでのKubernetes有効化
Kubernetes有効化設定の手順
MacのメニューバーにあるDockerアイコンをクリックすると、以下のようなメニューが表示されます。
ここから"Preferences"を選択すると、以下のような画面になります。
左のバーから"Kubernetes"を選択します。すると、Docker AppにおけるKubernetesの設定画面が以下のように表示されます。
この中から、"Enable Kubernetes"のチェックボックスに印を入れ、"Apply & Restart"で設定を保存します。
このような画面になるのでしばらく待機します。
ウィンドウ下部に「Kubernetes running」が表示されれば準備はOKです。起動確認
本当にKubernetesのサーバーが立ち上がったかどうかをコマンドで確認します。
$ kubectl version Client Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.5", GitCommit:"20c265fef0741dd71a66480e35bd69f18351daea", GitTreeState:"clean", BuildDate:"2019-10-15T19:16:51Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"darwin/amd64"} Server Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.5", GitCommit:"20c265fef0741dd71a66480e35bd69f18351daea", GitTreeState:"clean", BuildDate:"2019-10-15T19:07:57Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"linux/amd64"}先ほどは
Unable to connect to the server: EOF
と表示されていた部分にサーバーのバージョンが表示されています。無事に起動できたようです。また、Kubernetesを有効化したことで、Masterを構成するAPI ServerやSchedulerといった機能を担うコンテナイメージがpullされていることも確認できます。
# 以下のイメージが新規にpullされた $ docker images docker/desktop-storage-provisioner v1.0 605a0f683b7b 4 months ago 33.1MB k8s.gcr.io/kube-apiserver v1.15.5 e534b1952a0d 8 months ago 207MB k8s.gcr.io/kube-controller-manager v1.15.5 1399a72fa1a9 8 months ago 159MB k8s.gcr.io/kube-proxy v1.15.5 cbd7f21fec99 8 months ago 82.4MB k8s.gcr.io/kube-scheduler v1.15.5 fab2dded59dd 8 months ago 81.1MB docker/kube-compose-controller v0.4.23 a8c3d87a58e7 13 months ago 35.3MB docker/kube-compose-api-server v0.4.23 f3591b2cb223 13 months ago 49.9MB k8s.gcr.io/coredns 1.3.1 eb516548c180 17 months ago 40.3MB k8s.gcr.io/etcd 3.3.10 2c4adeb21b4f 19 months ago 258MB k8s.gcr.io/pause 3.1 da86e6ba6ca1 2 years ago 742kBそれなら、Masterを構成するコンテナがMac上で起動しているのか?と思ったのですが、
docker ps
では起動中のコマンドが確認できませんでした。$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
(おまけ)Kubernetes Dashboardの用意
「今のクラスターでは何が動いているのか?」「起動したPodはノードのリソース(CPUなど)をどれくらい食っているのか?」といった情報を、コマンドラインではなくGUIで確認できるようにするツールが存在します。それがKubernetes Dashboardです。
これはオプションツールなので、Kubernetesをインストールしただけの状態ではこれを持っていません。そのため、これを使いたい場合は個別にインストール・起動する必要があります。Dashboardのリソース作成(≒インストール)
Kubernetes Dashboardは、Kubernetesで作られたサービス(アプリ)という形で配布されています。
そのため、Dashboardを立ち上げるための設定ファイル(Kubernetesではマニュフェストファイルという)を参照して、その内容をローカルに展開・起動するという形をとります。
kubetcl apply
というコマンドで、マニュフェストファイルからDashboardのリソース作成を行います。-f
オプションで、インターネット上に公開されているDashboardのマニュフェストファイルを指定しています。$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta8/aio/deploy/recommended.yaml namespace/kubernetes-dashboard created serviceaccount/kubernetes-dashboard created service/kubernetes-dashboard created secret/kubernetes-dashboard-certs created secret/kubernetes-dashboard-csrf created secret/kubernetes-dashboard-key-holder created configmap/kubernetes-dashboard-settings created role.rbac.authorization.k8s.io/kubernetes-dashboard created clusterrole.rbac.authorization.k8s.io/kubernetes-dashboard created rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created clusterrolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created deployment.apps/kubernetes-dashboard created service/dashboard-metrics-scraper created deployment.apps/dashboard-metrics-scraper created参考:Kubernetes公式ドキュメント Web UI (Dashboard)
Dashboardログインのためのトークン取得
Dashboardにアクセスするためにはトークンによる認証が必要です。なので、そのトークンを確認します。
以下のコマンドを打って、default-token-*****
という名前のものを探します。$ kubectl -n kube-system get secret NAME TYPE DATA AGE (略) default-token-ss24c kubernetes.io/service-account-token 3 168m (略)ここでは
default-token-ss24c
というものが見つかりました。これを元に今度は以下のコマンドを打ちます。$ kubectl -n kube-system describe secret default-token-ss24c Name: default-token-ss24c Namespace: kube-system Labels: <none> Annotations: kubernetes.io/service-account.name: default kubernetes.io/service-account.uid: 92b6b004-dbf3-4593-adf0-fe2a2eb253f4 Type: kubernetes.io/service-account-token Data ==== ca.crt: 1025 bytes namespace: 11 bytes token: *********************ここに表示されているtokenをこの後利用するので、メモしておきましょう。
参考:Docker for Mac で Kubernetes をちょっと試す
プロキシサーバの起動
Dashboardサービスにアクセスするために、プロキシサーバを起動する。
以下のコマンドを打つことで、プロキシがフォアグラウンド稼働をします。(そのため、止めたくなった場合はCtrl+Cで停止できます。)$ kubectl proxy Starting to serve on 127.0.0.1:8001
ログイン
プロキシサーバを起動させた状態で、ブラウザで以下のアドレスにアクセスします。
http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/
Tokenを選択して、フォームに先ほど確認したトークンを入力します。後片付け
Dashboardのリソースを削除したい場合は、以下のコマンドで行えます。
$ kubectl delete -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta8/aio/deploy/recommended.yaml namespace "kubernetes-dashboard" deleted serviceaccount "kubernetes-dashboard" deleted service "kubernetes-dashboard" deleted secret "kubernetes-dashboard-certs" deleted secret "kubernetes-dashboard-csrf" deleted secret "kubernetes-dashboard-key-holder" deleted configmap "kubernetes-dashboard-settings" deleted role.rbac.authorization.k8s.io "kubernetes-dashboard" deleted clusterrole.rbac.authorization.k8s.io "kubernetes-dashboard" deleted rolebinding.rbac.authorization.k8s.io "kubernetes-dashboard" deleted clusterrolebinding.rbac.authorization.k8s.io "kubernetes-dashboard" deleted deployment.apps "kubernetes-dashboard" deleted service "dashboard-metrics-scraper" deleted deployment.apps "dashboard-metrics-scraper" deletedcontextの選択
Kubernetesを使う準備が整いました。これでクラスター上にPod等のリソースを作ってアプリを構築していくことができます。
しかし、ここで問題になるのが構築していく対象の設定です。
例えば、「クラスターAとクラスターBが現在存在していて、今はクラスターAを使いたい」という状況では、開発者が使うkubectl
コマンドでクラスターAのみがいじれないといけないわけです。
また、「クラスターA上でアプリチームがいじれるリソースと、同じクラスターAでインフラチームがいじれるリソースという風に触れる範囲を制御したい」という場合では、同じkubectl
コマンドでも同じ権限(機能)を持たせてはいけないことになります。この、「どのクラスターを、どの権限で
kubectl
コマンドで動かすのか」という設定集がcontextです。開発者は、手を入れたいリソースに合わせて、適切なcontextを選択・使用する必要があるわけです。contextの確認・変更
以下のコマンドで、現在存在するcontext一覧を確認することができます。
$ kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE * docker-desktop docker-desktop docker-desktop docker-for-desktop docker-desktop docker-desktop現在選択されているcontextは"docker-desktop"です。
"docker-for-desktop"に切り替えたい場合は、以下のようなコマンドを打ちます。$ kubectl config use-context docker-for-desktop Switched to context "docker-for-desktop". $ kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE docker-desktop docker-desktop docker-desktop * docker-for-desktop docker-desktop docker-desktop以下、ローカル上でのKubernetes操作は、この"docker-for-desktop"で行うこととします。
参考:[Kubernetes入門] kubectlのアクセス先(コンテキスト)を切り替える方法
ローカルで動いているクラスターの状態確認
Docker Appによって作られたクラスター(実態は、ローカルマシンというノード1台のみで構成)上には、デフォルトでどんな状態で作られているのかを確認してみましょう。
クラスター情報の確認
クラスターのMaster,DNSサーバーがどのアドレスで動いているのかが確認できます。
$ kubectl cluster-info Kubernetes master is running at https://kubernetes.docker.internal:6443 KubeDNS is running at https://kubernetes.docker.internal:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
クラスター内部からこれらのアドレスにアクセスすることによって、サービスを利用することができます。
ノードの確認
一覧取得
クラスター上で動いているノード一覧は、
kubectl get node
コマンドで取得できます。$ kubectl get node NAME STATUS ROLES AGE VERSION docker-desktop Ready master 24h v1.15.5
詳細情報取得
特定ノードの詳細な状態が知りたい場合は、
kubectl describe node
で確認できます。$ kubectl describe node <node-name>
Podの確認
一覧取得
クラスター上で動いているPod一覧も、
kubectl get pod
コマンドで取得できます。$ kubectl get pod -n kube-system NAME READY STATUS RESTARTS AGE coredns-5c98db65d4-qshvb 1/1 Running 1 44h coredns-5c98db65d4-zpbfq 1/1 Running 1 44h etcd-docker-desktop 1/1 Running 0 44h kube-apiserver-docker-desktop 1/1 Running 0 44h kube-controller-manager-docker-desktop 1/1 Running 0 44h kube-proxy-kd5kf 1/1 Running 0 44h kube-scheduler-docker-desktop 1/1 Running 0 44h storage-provisioner 1/1 Running 1 44h注: オプション
-n
は、後述する「名前空間」を指定するコマンドです。上の例の場合、クラスター上のkube-systemという名前空間で動いているPod一覧が取得されています。詳細情報取得
特定Podの詳細な状態が知りたい場合は、
kubectl describe pod
で確認できます。$ kubectl describe pods <pod-name>
ログ取得
Podででたログを確認したい場合は、以下のコマンドでログを標準出力に表示させることができます。
$ kubectl logs <pod-name>
Serviceの確認
Serviceとは
PodのIPアドレスは不定です。つまり、Pod起動のたびにIPアドレスが変化します。
そのため、そのPodを利用する側がIPアドレスの変化を気にすることなく、それらにアクセスするための単一エンドポイントが必要です。Kubernetesでその単一エンドポイントを作るための仕組みをサービスと呼びます。
(docker-composeにおいてコンテナのIPアドレスでアクセスするのではなく、サービスを作成してその名前でアクセスするのと同じです。)一覧取得
kubectl get service
コマンドで可能です。$ kubectl get service -n default NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 24h注:
-n
オプションの効果はPodのときと同じで、名前空間(後述)を指定するものです。詳細情報取得
kubectl describe service
で可能です。$ kubectl describe service <service-name>
名前空間の確認
名前空間とは
名前空間とは、1つの物理クラスターを論理的に分割して仮想のクラスターを作成する機能のことです。
例えば、「クラスターA上でアプリBとアプリCを両方同時に、干渉しないように動かしたい」という場合は、クラスターA上にアプリB用、アプリC用の名前空間を作成し、その名前空間上にそれぞれのアプリのPodやサービスをデプロイすることで、クラスターAを仮想的に二つの別クラスター空間と扱うことができます。
一覧取得
kubectl get namespace
コマンドで、現在のクラスター上に存在する名前空間を確認することができます。$ kubectl get namespace NAME STATUS AGE default Active 24h docker Active 24h kube-node-lease Active 24h kube-public Active 24h kube-system Active 24h kubernetes-dashboard Active 21h
デフォルトで作られる名前空間は以下の4つです。
- default
- kube-public
- kube-system
- kube-node-lease
また、Docker Appがある場合は"docker"名前空間が、Kubernetes Dashboardを入れている場合は"kubernetes-dashboard"名前空間があります。
default名前空間
デフォルトの名前空間です。
名前空間の指定が必要なリソース作成時にそれを指定しないと、自動的にdefault名前空間が使われます。kubectl get
等のコマンド実行時に-n
オプションをつけないときも、default名前空間上の情報が取得されます。
デフォルトでは1つのサービスが存在します。$ kubectl get all NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 45hこのサービスは、Master(≒API Server)にリクエストを送るためのものです。
参考:What's the purpose of the default kubernetes service?
kube-public名前空間
全contextからアクセス可能なリソースを配置するための空間です。
作成初期にリソースは存在しません。kube-system名前空間
Kubernetesシステムによって作成されたオブジェクト(API Serverなど)のための名前空間です。
ここに存在するリソースは以下の通りです。$ kubectl -n kube-system get all NAME READY STATUS RESTARTS AGE pod/coredns-5c98db65d4-qshvb 1/1 Running 1 44h pod/coredns-5c98db65d4-zpbfq 1/1 Running 1 44h pod/etcd-docker-desktop 1/1 Running 0 44h pod/kube-apiserver-docker-desktop 1/1 Running 0 44h pod/kube-controller-manager-docker-desktop 1/1 Running 0 44h pod/kube-proxy-kd5kf 1/1 Running 0 44h pod/kube-scheduler-docker-desktop 1/1 Running 0 44h pod/storage-provisioner 1/1 Running 1 44h NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 44h NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE daemonset.apps/kube-proxy 1 1 1 1 1 beta.kubernetes.io/os=linux 44h NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/coredns 2/2 2 2 44h NAME DESIRED CURRENT READY AGE replicaset.apps/coredns-5c98db65d4 2 2 2 44h
- pod/coredns: kube-dnsのサービスにアクセスがあったら、問い合わせが来るDNSサーバー
- pod/etcd-docker-desktop: etcd本体
- pod/kube-apiserver-docker-desktop: API Serverの本体
- pod/kube-controller-manager-docker-desktop: Controller Managerの本体
- pod/kube-proxy: サービスに接続するプロキシ
- pod/kube-scheduler-docker-desktop: Schedulerの本体
- pod/storage-provisioner: ストレージの割り当てを行う
- service/kube-dns: クラスター内に内蔵されているDNSサービス
時折「-docker-desktop」と付いているのは、「クラスターdoccker-desktop用」という意味だと思われます。
参考:Kubernetes公式ドキュメント Kubernetesのコンポーネント
kube-node-lease名前空間
Kubernetes 1.13から導入。NodeLeaseが有効になっている場合、各ノードはこの名前空間にオブジェクトを一つ作って、それを更新し続けることで死活監視を行います。
参考:Kubernetes公式ドキュメント ノードdocker名前空間
Kubernetesには、専用のマニュフェストファイルからだけではなく、
docker-compose.yml
からデプロイする機能が存在します。
この機能を提供するサービスはここに展開されているようです。
参考:Docker for MacでKubernetes構築 #composeとの統合kubernetes-dashboard名前空間
Kubernetes Dashboardをデプロイするための名前空間です。
詳細情報取得
特定の名前空間の詳しい状態が知りたい場合は、
kubectl describe
を使用します。$ kubectl describe namespace <name> Name: <name> Labels: <none> Annotations: <none> Status: Active No resource quota. No resource limits.
マニュフェストファイルを用いてアプリをデプロイ
ここからは、マニュフェストファイルでアプリ・コンテナの設定を記述して、それをローカルのKubernetes上にデプロイしていきたいと思います。
デプロイするアプリが1つだけの場合、名前空間はdefaultを使用するのが楽でしょう。
以下、特筆しない限り名前空間はdefaultです。Podを作ってみる
まず手始めに、Podを単独で作ってみましょう。
マニュフェストファイル作成
pod.yml
という名前でマニュフェストファイルを作成し、以下のように記述します。
今回は、MySQLのコンテナPodを作ってみます。pod.ymlapiVersion: v1 kind: Pod metadata: name: k8s-mysql labels: app: myapp tier: db spec: containers: - name: k8s-mysql image: mysql:5.7 volumeMounts: - name: k8s-mysql-storage mountPath: /var/lib/mysql ports: - containerPort: 3306 env: - name: MYSQL_ROOT_USER value: root - name: MYSQL_ROOT_PASSWORD value: pass - name: MYSQL_DATABASE value: sampledb volumes: - name: k8s-mysql-storage hostPath: path: /Users/myname/Desktop/k8s記述の意味は以下の通りです。
pod.yml# KubernetesのAPI Serverのバージョン apiVersion: v1 # マニュフェストファイルで何を作ろうとしているか。 kind: Pod # Podにつける識別子 metadata: # Pod名 name: k8s-mysql # この場合「key:app, value:myapp」「key:tier, value:db」という2つのラベルが付く labels: app: myapp tier: db # 作成するPodの定義 spec: # 所属するコンテナ containers: # コンテナの名前 - name: k8s-mysql # 使用するイメージ image: mysql:5.7 # マウントするボリュームの名前と、マウントさせるディレクトリパス(コンテナ内) volumeMounts: - name: k8s-mysql-storage mountPath: /var/lib/mysql # containerPortで、Podコンテナの何番ポートを開けるかを指定 ports: - containerPort: 3306 # コンテナに渡す環境変数 env: - name: MYSQL_ROOT_USER value: root - name: MYSQL_ROOT_PASSWORD value: pass - name: MYSQL_DATABASE value: sampledb # 所属するボリューム volumes: # ボリューム名 - name: k8s-mysql-storage # hostPathの場合、Podをホストするノード(ローカルの場合Kubernetesを動かしているPC)のどこのディレクトリにデータを保存するかの指定 hostPath: path: /Users/myname/Desktop/k8s参考:kubernetesによるDockerコンテナ管理入門
volumeについて参考:Kubernetesで使えるボリューム・タイプのチートシートローカルに存在するコンテナイメージを使いたい場合のマニュフェストファイルの記述
Docker Hubといったリポジトリに公開していない、自分のPCの中にあるイメージを使ってPodを作りたいという場合もあるでしょう。
その場合は、マニュフェストファイルを以下のように書きます。pod.yml(略) image: my-local-image-name # イメージを公開リポジトリから取らないという設定記述 imagePullPolicy: Never (略)参考:kubenetesでローカルコンテナイメージからコンテナを作成する方法
デプロイ
作成したマニュフェストファイルを元にリソースを作る場合は、
kubectl create
コマンドを使用します。$ kubectl create -f pod.yml後片付け
削除するときは
kubectl delete
を使います。$ kubectl delete -f pod.ymlなお、Podが削除されても、マウントされたボリューム(今回の場合はローカルPCの
/Users/myname/Desktop/k8s
)の中身はそのまま残ります。serviceを作ってみる
先ほど作成したMySQLのPodにエンドポイントを作るために、サービスを作成します。
マニュフェストファイルの作成
Pod作成のときと同様、まずはマニュフェストファイルを作成します。
service.ymlapiVersion: v1 kind: Service metadata: name: k8s-mysql-service labels: app: myapp spec: type: NodePort ports: - port: 3306 targetPort: 3306 protocol: TCP selector: app: myapp tier: db記述の意味は以下の通りです。
service.ymlapiVersion: v1 kind: Service metadata: # サービス名 name: k8s-mysql-service labels: app: myapp # 作成するサービスの定義 spec: # 全てのノードの3306番ポートにアクセスすることでこのサービスにアクセスされるようになる type: NodePort ports: # サービスがlistenするポート - port: 3306 # サービスが転送するpodのlistenポート targetPort: 3306 # 使用プロトコル protocol: TCP # 以下のlabelがついているpodをサービスの対象に含める(今回の場合、上記で作成したpodにつけた2つのラベルを指定) selector: app: myapp tier: db参考:Kubernetes道場 9日目 - Serviceについて
デプロイ
Pod同様、
kubectl create
で作成します。ただ、今回の場合はサービスと、その対象のPodの2つを作成する必要があります。
kubectl create
の-f
コマンドでマニュフェストファイルを複数指定してもいいのですが、面倒な場合は、マニュフェストファイルを一つのディレクトリにまとめて、そのディレクトリ以下にあるyamlファイル全てを作成対象にするというやり方をとります。# ./dirディレクトリ以下にあるファイル全てを参照する $ kubectl create -f ./dir./dir以下のymlファイルを全て見て、リソースを作る。
サービスにアクセスできるか確認
クラスター内でサービスに正しくアクセスできるかどうか確認してみましょう。
クラスター中にあるどれか1つのpodの中にログインして確かめてみます。
Podへのログインは以下のコマンドで行えます。$ kubectl exec -it <podname> -- /bin/bashまずは、サービスに接続するためにはどんなドメインを使えばいいのかを調べてみましょう。
# podの中で実行 # dig, nslookupといったDNS接続確認を行うコマンドをインストール $ apt update $ apt get install dnsutils # サービス名でnslookup $ nslookup k8s-mysql-service Server: 10.96.0.10 Address: 10.96.0.10#53 Name: k8s-mysql-service.default.svc.cluster.local Address: 10.110.179.176 # サービス名でdig $ dig k8s-mysql-service ; <<>> DiG 9.11.5-P4-5.1+deb10u1-Debian <<>> k8s-mysql-service ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 34032 ;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ; COOKIE: 4529e3e33e3e0a28 (echoed) ;; QUESTION SECTION: ;k8s-mysql-service. IN A ;; Query time: 34 msec ;; SERVER: 10.96.0.10#53(10.96.0.10) ;; WHEN: Mon Jul 06 17:16:29 UTC 2020 ;; MSG SIZE rcvd: 58どちらのコマンドでも、マニュフェストファイルで指定したサービス名
k8s-mysql-service
でアクセスできることが確認できました。また、
nslookup
コマンドで取得できたIPアドレス10.110.179.176
は、kubectl describe
で確認できるサービスのIPと一致します。# ローカルで実行 $ kubectl describe service k8s-mysql-service #(略) IP: 10.110.179.176 #(略)この名前解決を利用して、クラスター内からMySQLサービスに接続してみましょう。
# Pod内で実行 # mysqlサービスへのアクセス確認のため、sqlクライアントのインストールを行う $ apt-get install default-mysql-client $ mysql -h k8s-mysql-service -u root -p Enter password: MySQL [(none)]>このように、サービス名を使うことで接続できました。
serviceにMacのローカルホストを接続
Kubernetes Dashboardのように、起動しているサービスにクラスタ外のMacから接続したい!という状況があると思います。
例えばweb-service
という名前のサービスを作り、そのサービスにMacのLocalhostを繋ぎブラウザ閲覧したいとします。
この場合、マニュフェストファイルを以下のように作ります。web.ymlapiVersion: v1 kind: Service metadata: name: web-service labels: app: myapp spec: # ここのtypeをLoadBalancerにすることが重要 type: LoadBalancer ports: - port: 9090 targetPort: 9090 protocol: TCP selector: app: myapp tier: webこのサービスをデプロイして、
kubectl get
で情報を確認してみます。$ kubectl get service (略) NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/web-service NodePort 10.101.53.215 localhost 8080:31392/TCP 4sこの場合、
web-service
にはMacのhttp://localhost:8080
でアクセスすることができます。サービスのTypeについて
今回、NodeTypeやLoadBalancerといった種類のサービスを扱いましたが、それぞれのネットワーク構成については、以下の記事がわかりやすいので紹介しておきます。
参考:Kubernetes ネットワーク構成developmentを作ってみる
Pod定義でコンテナを増やしていってもいいのですが、今後の運用面を考えてコンテナはdevelopmentという形でデプロイしましょう。
developmentとは
developmentは、ReplicaSet(レプリカセット)を管理するための仕組みです。
まず、レプリカセットについて説明します。
例えば、同じPodを複数個作って冗長化したい!という場合は、Pod単独をいくつも繰り返し作るのではなく、レプリカセットという、「Podと作りたい個数を指定することで、指定Podのコピーを指定数だけ作る」機能で作ります。
(ECSでサービスを作成する際に、タスクを同時に何個起動させるかを選択するのと思想は同じです)また、Podの内容を更新したい!というときは、レプリカセット単独ではなく、development中のレプリカセットという形でデプロイすることで、Podの自動更新・ロールバック等の運用操作が簡単にできるようになります。
それぞれの関係としては、Deployment → ReplicaSet → Podという包含関係になります。
つまり、developmentの中にレプリカセット(≒複数個のPodのコピー)を入れることで、バージョン管理や、複数個のPodをまとめて運用しやすくしているのです。参考:Kubernetes: Deployment の仕組み
マニュフェストファイルの作成
先ほど作ったMySQLのPodをdevelopmentに直してみます。
以下のようなファイルを作ります。dev.ymlapiVersion: apps/v1 kind: Deployment metadata: name: mysql-development spec: replicas: 2 selector: matchLabels: app: myapp template: metadata: labels: app: myapp tier: db spec: containers: - name: k8s-mysql image: mysql:5.7 volumeMounts: - name: k8s-mysql-storage mountPath: /var/lib/mysql ports: - containerPort: 3306 env: - name: MYSQL_ROOT_USER value: root - name: MYSQL_ROOT_PASSWORD value: pass - name: MYSQL_DATABASE value: sampledb volumes: - name: k8s-mysql-storage hostPath: path: /Users/myname/Desktop/k8s記述の意味は以下の通りです。
dev.ymlapiVersion: apps/v1 kind: Deployment metadata: # developmentの名前 name: mysql-development # developmentで作る状態について記述 spec: # レプリカセットの数 replicas: 2 # developmentが管理するリソースのラベル selector: matchLabels: app: myapp # developmentで管理するものの一覧 template: # Pod, volumeにつけるラベル metadata: labels: app: myapp tier: db # 以下はPod定義のときと同じ記述 spec: containers: - name: k8s-mysql image: mysql:5.7 volumeMounts: - name: k8s-mysql-storage mountPath: /var/lib/mysql ports: - containerPort: 3306 env: - name: MYSQL_ROOT_USER value: root - name: MYSQL_ROOT_PASSWORD value: pass - name: MYSQL_DATABASE value: sampledb volumes: - name: k8s-mysql-storage hostPath: path: /Users/myname/Desktop/k8s参考:Kubernetes公式ドキュメント Deployment
参考:DeploymentとServiceをyamlファイルで定義するデプロイ・後片付け
Podやサービス同様、
kubectl create/delete
を使って行います。$ kubectl create -f dev.yml $ kubectl delete -f dev.ymlEKSにデプロイ
ローカルで簡単な操作ができてコツをつかんだところで、いよいよ本番環境に乗せていきます。
今回は、AWSのEKSを利用します。EKS上にクラスターを作成
クラスター作成の2つのやり方比較
まずは、EKS上にクラスターを作成します。
やり方は2つあり、1つはAWSのWebコンソール上で作成操作を行うやり方、もう1つはターミナルからeksctl
コマンドを用いて作成操作を行うやり方です。今回は
eksctl
コマンドを用いた方法でクラスター作成を行います。なぜかというと設定が圧倒的に楽だからです。
eksctl
を用いることで、以下の設定が自動的に行われます。
- EKSクラスターに属するノードに与えるIAMロール作成
- VPCネットワーク/サブネット/ルートテーブル/IGW/NATゲートウェイの作成
- セキュリティグループの作成
- EKSクラスターヘの
kubectl
の接続Webコンソールでクラスター作成を行なった場合、このような煩雑な設定を手動でやる必要があります。複雑な構成にしたいのではない場合は、
eksctl
コマンドを使用するのが効率的でしょう。参考:「eksctl」コマンドを使ったAmazon EKS構築入門
eksctl
コマンドのインストールEKSにクラスターを作るための
eksctl
コマンドをインストールします。
(できたクラスターを操作するのは、ローカルのときと同様にkubectl
コマンドです。eksctl
にできるのはあくまでクラスター関連の操作だけです。)ターミナルで以下のコマンドを実行します。
$ brew tap weaveworks/tap $ brew install weaveworks/tap/eksctl #ダウンロードできたかは以下のコマンドで確認 $ which eksctl /usr/local/bin/eksctl参考:AWS公式ドキュメント eksctl コマンドラインユーティリティ
クラスター作成コマンド実行
早速コマンドを打ってクラスターを作成します。
$ eksctl create cluster \ --vpc-cidr 10.0.0.0/16 \ --name eks-sample \ --region ap-northeast-1 \ --version 1.14 \ --nodegroup-name sample-workers \ --node-type t2.micro \ --nodes 1 \ --nodes-min 1 \ --nodes-max 3 \ --managedオプションの意味は以下の通りです。
- vpc-cidr: 新規作成するVPCのCIDR
- name: クラスター名
- region: リージョン。東京リージョンを使いたいのでap-northeast-1を指定
- version: Kubernetesのバージョン
- nodegroup-name: ノードグループ(EKSクラスターに属するEC2インスタンスノード集団のこと)の名前
- node-type: ノードに使うマシンのタイプ
- nodes: 起動時点でのノード数
- nodes-min: 最小ノード数
- nodes-max: 最大ノード数
- managed: ノードグループをWebコンソール上で表示・いじれるようにする
参考:eksctlを使った簡単Amazon EKS環境構築
参考:[アップデート] EKSがマネジメントコンソールおよびCLIでのワーカーノードの作成・管理をサポートしました実行には結構時間がかかりますので気長に待ちましょう。
結果
クラスターがちゃんとできてます。
コマンドでもその結果が確認できます。# EKS上のクラスター一覧 $ eksctl get cluster NAME REGION eks-sample ap-northeast-1 # eks-sampleというクラスター上にあるnodegroupの確認 $ eksctl get nodegroup --cluster eks-sample CLUSTER NODEGROUP CREATED MIN SIZE MAX SIZE DESIRED CAPACITY INSTANCE TYPE IMAGE ID eks-sample sample-workers 2020-07-11T04:57:37Z 1 3 1 t2.microクラスターができるに当たって、以下のものが自動で作成されました。
- VPC: 新しいものが1つ
- サブネット: ap-northeast-1にある3つのAZにそれぞれ2個ずつ
- ルートテーブル: パブリックサブネット用が1つ、プライベートサブネット用が3つのAZにそれぞれ1つずつ、新しいVPCのデフォルトルートテーブル1つの計5つ
- インターネットゲートウェイ: 新しいVPC用に1つ
- Elastic IP: 新しいVPCのNATゲートウェイ用に1つ
- NATゲートウェイ: 1つ
- セキュリティグループ: 新しいVPCのデフォルト1つと、EKSが作ったもの3つ
↓サブネットの様子
↓ルートテーブルの様子
↓セキュリティグループの様子
結果的に、以下のような構成の環境が出来上がっています。
画像出典:EKS公式ドキュメント スケーラブルなモジュール式 Amazon EKS アーキテクチャ
kubectl
の設定EKS上のクラスターにリソースをデプロイするのは、ローカル同様
kubectl
だという話は先ほどしました。
しかし、そのためにはkubectl
コマンドで、ローカルではなくてEKSクラスターを選択するような設定が必要になります。contextの確認
「どのクラスターを
kubectl
でいじるか」という設定は上述したcontextの選択で行います。
EKSクラスター作成後、存在するcontext一覧を確認してみましょう。$ kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE docker-desktop docker-desktop docker-desktop docker-for-desktop docker-desktop docker-desktop * myname@eks-sample.ap-northeast-1.eksctl.io eks-sample.ap-northeast-1.eksctl.io myname@eks-sample.ap-northeast-1.eksctl.ioなんと、EKSクラスターをいじる用のcontextが自動作成・選択されていました。これは
eksctl
でクラスターを作成したからこそ行われたものです。
(WebコンソールでEKSクラスターを作成したら、これも手動で行います。eksctl
コマンドの便利さがこれでわかりますね。)kubeconfigの確認
なぜ
eksctl
コマンドを実行しただけで、自動でEKS用のcontextが追加・選択されていたのでしょうか。
それはコマンド実行時にkubeconfigという設定ファイルが自動で編集されていたからです。kubeconfigファイルの中身を見てみましょう。以下のようにコマンドを打ってみます。
$ kubectl config view apiVersion: v1 clusters: - cluster: certificate-authority-data: seeeeeeeeecret server: https://kubernetes.docker.internal:6443 name: docker-desktop - cluster: # EKSコンソールで確認できる認証機関の値 certificate-authority-data: seeeeeeeeecret # EKSコンソールで確認できるAPIサーバーエンドポイントのアドレス server: https://********************.***.ap-northeast-1.eks.amazonaws.com name: eks-sample.ap-northeast-1.eksctl.io contexts: - context: cluster: docker-desktop user: docker-desktop name: docker-desktop - context: cluster: docker-desktop user: docker-desktop name: docker-for-desktop - context: cluster: eks-sample.ap-northeast-1.eksctl.io user: myname@eks-sample.ap-northeast-1.eksctl.io name: myname@eks-sample.ap-northeast-1.eksctl.io current-context: myname@eks-sample.ap-northeast-1.eksctl.io kind: Config preferences: {} users: - name: docker-desktop user: client-certificate-data: seeeeeeeeecret client-key-data: seeeeeeeeecret - name: myname@eks-sample.ap-northeast-1.eksctl.io user: exec: apiVersion: client.authentication.k8s.io/v1alpha1 args: - token - -i - eks-sample command: aws-iam-authenticator env: - name: AWS_STS_REGIONAL_ENDPOINTS value: regional - name: AWS_DEFAULT_REGION value: ap-northeast-1これは
$HOME/.kube/config
にある設定ファイルの中身がそのまま出力されている様子です。何もしていないのに、明らかにAWS用の設定と思われる箇所が存在します。
このように、kubeconfigに、EKSのクラスターに接続できるようなcontext設定が自動で追加されていることがここからもわかります。
kubectl
の認証トークン設定ローカル側で
kubectl
の対象クラスターをEKSに向けることはできました。しかし、EKS側ではkubectl
コマンドでアクセスしてきた人が正規の権限を持った開発者であるとどのように認識しているのでしょうか。EKSでは、クライアントにIAM認証情報から得たトークンを
kubectl
コマンド実行時に付与してもらい、そのトークンを見ることで、正規の権限を持った人かどうかを判定しています。そのため、EKSクラスターを操作するためのcontextで、
kubectl
コマンド実行時に認証トークンを渡すように設定する必要があります。
やり方は2つあります。aws-iam-authenticator
コマンドを使う方法とaws eks get-token
コマンドを使う方法です。
aws-iam-authenticator
コマンドの方法デフォルトではこちらの方法になっています。
aws-iam-authenticator
コマンドがインストール済みの方はこちらを使えば余計な手間がかからなくてよいでしょう。
kubeconfigの以下の記述の部分が該当箇所です。$HOME/.kube/configargs: - token - -i - eks-sample command: aws-iam-authenticator
aws eks get-token
コマンドの方法
aws-iam-authenticator
コマンドはないがaws
コマンドはある!という方はこちらの方法をとれば何もインストールしなくても大丈夫です。
上記のkubeconfig($HOME/.kube/config
に存在)の記述部分を、以下のように書き換えます。$HOME/.kube/config#args: #- token #- -i #- eks-sample #command: aws-iam-authenticator args: - eks - get-token - --cluster-name - eks-sample command: aws参考:[アップデート]EKSを使う際にaws-iam-authenticatorが不要になりました!
kubectl
がEKSクラスターを向いていることを実際のコマンドで確認ここまでの準備ができたところで、ノード一覧を取得してみましょう。
$ kubectl get node NAME STATUS ROLES AGE VERSION ip-10-0-13-242.ap-northeast-1.compute.internal Ready <none> 85s v1.15.11-eks-908ff6
明らかにAWS上のリソースが取得できました。
eksctl
コマンドで指定した通り、ノードが1つ作成されていることがわかります。EKSクラスター上にリソース作成
kubectl
コマンドでEKSクラスターを扱えるようになったので、いよいよEKS上にリソースを作成してみましょう。マニュフェストファイルの修正(適宜)
もしもデプロイするコンテナのイメージとして、ECR上のイメージを使いたい!という場合は、マニュフェストファイルのコンテナイメージを指定する箇所を、ECRのリポジトリURIに書き換えればOKです。
dev.yml# 以下は一例です (略) image: your-aws-account-id.dkr.ecr.ap-northeast-1.amazonaws.com/myapp/api:v1 (略)デプロイ/削除
ローカル同様、
kubectl create/delete
コマンドを実行します。$ kubectl create -f dev.yml deployment.apps/myapp-mysql created $ kubectl delete -f dev.yml deployment.apps/myapp-mysql deletedまた、LoadBalancer型のサービスをデプロイした場合、自動的にELBが作成→当該サービスとの紐付けが行われています。
例えば、LoadBalancer型のサービスがあるとき、kubectl get
コマンドを実行し情報を確認してみます。$ kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE (略) myservice LoadBalancer 172.20.78.107 *******.ap-northeast-1.elb.amazonaws.com 9090:31806/TCP 7m25sEXTERNAK-IPの部分に表示されているドメインは、自動作成されたELBのアドレスです。
そのため、http://*******.ap-northeast-1.elb.amazonaws.com:9090
にブラウザからアクセスすれば、そのサービスにWebからアクセスすることができます。
参考:Amazon EKS のチュートリアルで Kubernetes を理解する #02 アプリのデプロイ後片付け
使い終わったらEKS環境を片付けましょう。
デプロイしたリソースをkubectl delete
するのはもちろん、余計な費用がかからないようにEKSクラスターも以下のように削除しましょう。$ eksctl delete cluster --name=eks-sampleこれを実行することで、クラスター作成時に自動で作られたVPCやNATゲートウェイなども全てなくなります。また、kubeconfigに書かれたEKS用の設定記述も自動で消去されます。
- 投稿日:2020-07-13T13:16:20+09:00
Railsコマンド叩くとコンテナが落ちてたけどECSのメモリとCPUの設定を変えたら直った話
結論
下記のようにECSのコンテナメモリとCPUユニット数を変更したら直った
(フリー画像です)事象
- コンテナに入ってRailsコマンドを叩くとコンテナが落ちる
- 502 Bad Gatewayで画面表示さえされない時もあった
- なぜか本番環境では落ちてなかった
- ステージング環境だけ落ちてた → ECSのインスタンスが落ちては自動立ち上げの無限ループ
- Rails 6系にバージョンアップするとステージング環境の画面も表示されるようになった
- 相変わらずRailsコマンドを叩くとコンテナは落ちた
EC2のインスタンスタイプ
- 本番環境:m4.large
- ステージング環境:t3.large
参考資料
試したことメモ
- Railsコマンドテスト
rails -v
は問題なかった。ほかRailsコマンドはダメなのでRailsアプリ内のスクリプトが動くとだめなのかも?- spring killしてRailsコマンド実施
- springを起動しない設定の
DISABLE_SPRING=1
を環境変数に設定してRailsコマンド実施- 直接指定 →
$ DISABLE_SPRING=1 RAILS_ENV=staging ./bin/rails console
- 環境変数とか見直し
- Railsバージョンを上げてみた
- Railsコマンドが走ってた場所まで戻して試してみた
- topで実行プロセス見てみた → springじゃね?に繋がる
- タスク定義の不要なやつを削除してみた
- ほかAWSで紐づけている設定見直し
- ECSのメモリ制限をハード制限・ソフト制限ともに3000MiBに設定
まとめ
多分ECSコンテナの要領不足。な気がします。
メモリよりCPUユニット数の方が決定打でした。EC2のインスタンスタイプも適当に設定しちゃダメだと痛感しました。
インフラ周り疎いので詳しい方いたら教えてください。余談
ちなみにコンテナCPUを500 → 1024に設定するとタスク定義が更新できなくなってしまった。
適切なユニット数を設定するのが大事みたい。
→ CPU1024MiBにすると、ECS常時2インスタンスだとして、切り替えのタイミングで2→4になり1024MiB*4が要求されて要領を超えてしまってた
- 投稿日:2020-07-13T11:41:58+09:00
DBサーバーの秘密鍵(mykey-private.pem)の作成方法
「AWS 踏み台サーバー経由のSSH」
上記、記事ありがとうございます。私は超初心者で、『Amazon Web Services 基礎からのネットワーク&サーバー構築』の改訂3版の通り進めていて、P148の秘密鍵のところで、躓いてしまいました。 上記に
>インスタンス②の秘密鍵はmy-key-private.pem なので、
とありますが、テキストでは、このインスタンスの秘密鍵を作成する場面はなかったと思います。そこで、戻ってインスタンス①の秘密鍵と同じようにmy-key-private.pem を作成しようとしているのですが、うまくいきません。
1)既にできているセキュリティグループDB-SGに基づいて、インスタンス②の秘密鍵を作るか、
2)DB-SGを削除して、その作成からすすめて秘密鍵を作るか、
どちらでも、結構です。何らかのヒントでもいただければ幸いです。
- 投稿日:2020-07-13T09:32:44+09:00
AWS基本事項メモ(主にEC2関連)
AMI(Amazon Machine Image)とは
インスタンス軌道に必要なテンプレート情報が入ったOSのイメージ。サーバーのテンプレートのようなもの。
AWSやサードパーティのAMIの他、カスタムAMIを作ることも可能。
カスタムAMIから、複数のインスタンスを作ることも可能。インスタンス
EC2から立てられたサーバーのこと。
以下はインスタンスを立てる時に必要な事項インスタンスタイプ
サーバーのスペックを定義したもの。
「m5.xlarge」
- インスタンスタイプの名前の表記の意味
- 「m」 インスタンスファミリー(どのような特徴を持ったインスタンスかの種類を表したもの)
- 「5」 インスタンス世代(基本的に新しい世代がコスパが良い場合が多いので良い)
- 「xlarge」 インスタンスサイズ(スペックの高低)
ストレージ
サーバにくっつけるデータの保管場所。EC2には以下の2種類ある。
- EBS
- 高い可用性と耐久性を持つストレージ
- 他のインスタンスにも付け替え可能。
- EC2インスタンスをstop/terminateしてもデータの保持が可能。
- S3を利用してスナップショットを保存可能
- EBSの別料金がかかる
- OSやDBなどの永続性と耐久性が必要なデータを置く
- HDDのようなイメージ
- インスタンスストア
- インスタンス専用のストレージ
- 他のインスタンスには付け替えられない。
- EC2インスタンスをstop/terminateするとデータが消える
- 追加料金はかからない。
- 無くなってはいけないデータは置けない
- 一時ファイル、キャッシュなど無くなっても構わないデータに向く
ssh
SucureShellの略で安全に通信を行って、ネットワークに接続された機器を遠隔操作するための通信手段。
例えば自分のPCからssh接続でAWSのEC2インスタンス内に入って作業することができる。
サーバ内に公開鍵を置いておき、秘密鍵を持っているユーザーのみ接続できる。
EC2作成時に作成できるpemファイルなどはこの秘密鍵ポート番号
IPアドレスがインターネット上でコンピュータを識別するアドレスなのに対して、ポート番号はプログラムのアドレスと表現することができる。
プログラムごとにポート番号が決まっている。
IPアドレスで、コンピュータを指定し、ポート番号でそのコンピュータ内の通信したい対象のプログラムを指定するイメージ。例えばssh接続であるサーバに接続したいとき、
- 接続したいサーバAのIPアドレス
- 178.10.0.10
- そのサーバで走っているプログラムにそれぞれ割り当てられているポート番号が
- sshサーバ(具体的にはsshdプログラム)が22
- httpプログラム(サーバ)が80
- SMPTプログラム(サーバ)が25
の場合、
自分のPCから「178.10.0.10」のポート番号22に接続する」と通信を送ると、サーバAにssh接続する。ウェルノウンポート番号と言って大体のサーバで標準的なポート番号は決まっていて、例えば
- sshサーバが22
- httpサーバが80
- httpsサーバは443
- SMPTサーバが25
- 以上となっている。逆にクライアント側ポート番号は動的に決められたりする。
サーバ内で以下のコマンドを実行すると、ポート番号一覧が取得できる。
sudo lsof -i -n -P //-n:ipアドレスとホスト名に変換しないオプション -P:ポート番号をサービス名に変換しないオプション。ファイアーウォール設定(セキュリティグループ)
ES2インスタンスではセキュリティ上デフォルトではインバウンド(サーバへのアクセス)はssh接続のポート番号22への接続以外は受け付けないようになっている。サーバを外部公開するにはhttp80かhttps443のポートへの接続を受け付けるようにセキュリティグループを設定する必要がある。
Elastic IP アドレス
インターネット経由でアクセス可能な固定グローバルIPアドレスを取得し、インスタンスに付与できるサービス。
通常EC2インスタンス(サーバ)は停止、再起動をするとIPアドレスが変わってしまう為、これでIPアドレスを固定化する。
インスタンスを削除するまでは基本的にずっと固定のIPアドレスを使える。
インスタンスと紐づけられていて、そのインスタンスが起動中は無料、そうでない場合は有料。
逆に言うとElastic IPアドレスが使われていないと課金されるので、使わない場合は都度解放する。
- 投稿日:2020-07-13T07:48:51+09:00
水樹奈々さん公式サイトも使う? S3,Cloudfont,Route53をコマンド一発でデプロイするslsテンプレ
水樹奈々さんのHPがAWSを使っていると話題になりましたが、Route53・S3・Cloudfrontを連携させる設定はAWS初見の人では難しく感じると思います。私がそうでした。
今はSeverless Frameworkを使い、一発でデプロイするファイルを作成して運用しているので、公開します。
Githubはこちら、デモページはこちらです。
テンプレは以下の環境で動作・デプロイされます。適宜読み替えてください。
umihi.co
というドメインをroute53で管理している。us-east-1
のACMにてumihi.co
と*.umihi.co
を1つとして証明書を発行している。- サブドメイン
sls-static-website.umihi.co
として静的サイトをデプロイする以下のファイルを作成し、
AcmCertificateArn
と、ドメイン各所の書き換えを行いsls deploy
でデプロイします。分かりやすさ重視でなるべくハードコーディングしています。serverless.yamlservice: sls-static-website provider: name: aws runtime: provided stage: dev region: ap-northeast-1 resources: Resources: WebsiteBucket: Type: AWS::S3::Bucket Properties: BucketName: sls-static-website.umihi.co WebsiteConfiguration: IndexDocument: index.html ErrorDocument: 404.html DeletionPolicy: Retain WebsiteCloudfront: Type: AWS::CloudFront::Distribution DependsOn: - WebsiteBucket Properties: DistributionConfig: Origins: - DomainName: sls-static-website.umihi.co.s3-website-ap-northeast-1.amazonaws.com Id: S3Origin CustomOriginConfig: HTTPPort: '80' HTTPSPort: '443' OriginProtocolPolicy: http-only Enabled: true HttpVersion: 'http2' DefaultRootObject: index.html Aliases: - sls-static-website.umihi.co DefaultCacheBehavior: AllowedMethods: - GET - HEAD Compress: true TargetOriginId: S3Origin ForwardedValues: QueryString: true Cookies: Forward: none ViewerProtocolPolicy: redirect-to-https PriceClass: PriceClass_All ViewerCertificate: AcmCertificateArn: arn:aws:acm:us-east-1:123456789:certificate/xxxxxxxx-yyyy-zzzz-aaaa-123456789 # must be in us-east-1 SslSupportMethod: sni-only WebsiteDNSName: Type: AWS::Route53::RecordSetGroup Properties: HostedZoneName: umihi.co. # you need (.)period at the end RecordSets: - Name: sls-static-website.umihi.co. # you need (.)period at the end Type: A AliasTarget: HostedZoneId: Z2FDTNDATAQYW2 # This is always the hosted zone ID when you create an alias record that routes traffic to a CloudFront distribution. # DNSName: ddddxxxxyyyyzzzzz.cloudfront.net # you can also hard-code like this DNSName: Fn::GetAtt: [ WebsiteCloudfront, DomainName ]作成時にハマったのは
- route53の
HostedZoneName
やRecordSets.Name
の値には末尾にピリオドが必要がある。- S3にアップロード・更新しても、Cloudfrontがキャッシュを持つと反映されないので都度Invalidationする必要がある
- CloudfrontのOrigin設定の
DomainName
で補完で候補に表示されるsls-static-website.umihi.co.s3.amazonaws.com
ではなく、 Static Website Hostingのエンドポイントのsls-static-website.umihi.co.s3-website-ap-northeast-1.amazonaws.com
を使わないと、この構成だとリダイレクトのループになった。リダイレクト問題自体は解決せず分からなかったのですが仮に解決したら、どちらのエンドポイントを使うべきかはこちらが参考になりました。
バケットにファイルを手動でアップロードすると、公開する作業が必要になります。serverless-s3-syncを使い設定すればデプロイ時にローカルファイルを常に同期することが可能になり、公開作業も不要になります。Githubレポジトリの
serverless.yml
にはその設定も含まれているので、参考にしてください。参考
- https://github.com/sjevs/cloudformation-s3-static-website-with-cloudfront-and-route-53/blob/master/s3-static-website-with-cloudfront-and-route-53.yaml
- https://gist.github.com/matalo33/fc2a9d8698c069e134b4b0b6640f0c84
- https://github.com/awslabs/aws-cloudformation-templates/blob/master/aws/services/S3/S3_Website_With_CloudFront_Distribution.yaml
- https://masaru-tech.hateblo.jp/entry/2018/03/27/111327
- https://qiita.com/NaokiIshimura/items/46994e67b712831c3016
- https://forum.serverless.com/t/unclear-how-to-reference-lambda-role-arn-in-serverless-yml/1147/5
- https://simonecarletti.com/blog/2016/08/redirect-domain-https-amazon-cloudfront/
- https://stackoverflow.com/questions/43835731/301-redirect-for-specific-page-with-cloudfront
- 投稿日:2020-07-13T07:48:51+09:00
静的サイトの鉄板構成であるS3,Cloudfont,Route53をコマンド一発でデプロイするslsテンプレ
Route53・S3・Cloudfrontを連携させる設定はAWS初見の人では難しく感じると思います。私がそうでした。
今はSeverless Frameworkを使い、一発でデプロイするファイルを作成して運用しているので、公開します。
Githubはこちら、デモページはこちらです。
テンプレは以下の環境で動作・デプロイされます。適宜読み替えてください。
umihi.co
というドメインをroute53で管理している。us-east-1
のACMにてumihi.co
と*.umihi.co
を1つとして証明書を発行している。- サブドメイン
sls-static-website.umihi.co
として静的サイトをデプロイする以下のファイルを作成し、
AcmCertificateArn
と、ドメイン各所の書き換えを行いsls deploy
でデプロイします。分かりやすさ重視でなるべくハードコーディングしています。serverless.yamlservice: sls-static-website provider: name: aws runtime: provided stage: dev region: ap-northeast-1 resources: Resources: WebsiteBucket: Type: AWS::S3::Bucket Properties: BucketName: sls-static-website.umihi.co WebsiteConfiguration: IndexDocument: index.html ErrorDocument: 404.html DeletionPolicy: Retain WebsiteCloudfront: Type: AWS::CloudFront::Distribution DependsOn: - WebsiteBucket Properties: DistributionConfig: Origins: - DomainName: sls-static-website.umihi.co.s3-website-ap-northeast-1.amazonaws.com Id: S3Origin CustomOriginConfig: HTTPPort: '80' HTTPSPort: '443' OriginProtocolPolicy: http-only Enabled: true HttpVersion: 'http2' DefaultRootObject: index.html Aliases: - sls-static-website.umihi.co DefaultCacheBehavior: AllowedMethods: - GET - HEAD Compress: true TargetOriginId: S3Origin ForwardedValues: QueryString: true Cookies: Forward: none ViewerProtocolPolicy: redirect-to-https PriceClass: PriceClass_All ViewerCertificate: AcmCertificateArn: arn:aws:acm:us-east-1:123456789:certificate/xxxxxxxx-yyyy-zzzz-aaaa-123456789 # must be in us-east-1 SslSupportMethod: sni-only WebsiteDNSName: Type: AWS::Route53::RecordSetGroup Properties: HostedZoneName: umihi.co. # you need (.)period at the end RecordSets: - Name: sls-static-website.umihi.co. # you need (.)period at the end Type: A AliasTarget: HostedZoneId: Z2FDTNDATAQYW2 # This is always the hosted zone ID when you create an alias record that routes traffic to a CloudFront distribution. # DNSName: ddddxxxxyyyyzzzzz.cloudfront.net # you can also hard-code like this DNSName: Fn::GetAtt: [ WebsiteCloudfront, DomainName ]作成時にハマったのは
- route53の
HostedZoneName
やRecordSets.Name
の値には末尾にピリオドが必要がある。- S3にアップロード・更新しても、Cloudfrontがキャッシュを持つと反映されないので都度Invalidationする必要がある
- CloudfrontのOrigin設定の
DomainName
で補完で候補に表示されるsls-static-website.umihi.co.s3.amazonaws.com
ではなく、 Static Website Hostingのエンドポイントのsls-static-website.umihi.co.s3-website-ap-northeast-1.amazonaws.com
を使わないと、この構成だとリダイレクトのループになった。リダイレクト問題自体は解決せず分からなかったのですが仮に解決したら、どちらのエンドポイントを使うべきかはこちらが参考になりました。
バケットにファイルを手動でアップロードすると、公開する作業が必要になります。serverless-s3-syncを使い設定すればデプロイ時にローカルファイルを常に同期することが可能になり、公開作業も不要になります。Githubレポジトリの
serverless.yml
にはその設定も含まれているので、参考にしてください。参考
- https://github.com/sjevs/cloudformation-s3-static-website-with-cloudfront-and-route-53/blob/master/s3-static-website-with-cloudfront-and-route-53.yaml
- https://gist.github.com/matalo33/fc2a9d8698c069e134b4b0b6640f0c84
- https://github.com/awslabs/aws-cloudformation-templates/blob/master/aws/services/S3/S3_Website_With_CloudFront_Distribution.yaml
- https://masaru-tech.hateblo.jp/entry/2018/03/27/111327
- https://qiita.com/NaokiIshimura/items/46994e67b712831c3016
- https://forum.serverless.com/t/unclear-how-to-reference-lambda-role-arn-in-serverless-yml/1147/5
- https://simonecarletti.com/blog/2016/08/redirect-domain-https-amazon-cloudfront/
- https://stackoverflow.com/questions/43835731/301-redirect-for-specific-page-with-cloudfront
- 投稿日:2020-07-13T00:44:00+09:00
【Capistrano,Unicorn】ArgumentError: directory for pid=/var/www/badsuru/current/shared/tmp/pids/unicorn.pid not writableが書き込み権限の問題ではなかった
はじめに
Capistranoを用いた自動デプロイ中、タイトルのエラーが出てほぼ1日を費やしました・・・
結論、大したことではなく自分にがっかりしてしまいましたが、同じようなエラーで悩む方の手助けになれば幸いです。対象者
- 初学者
- Capistrano設定中の方
- Unicorn使用者
開発環境
- Rails 6.0.3.1
- ruby 2.7.1
- unicorn 5.4.1
- AWS Amazon Linux AMI 2018.03.0 (HVM), SSD Volume Type
この記事を通じて得られること
- タイトルのエラーの原因・解決方法 ※あくまで1つのエラーの解決方法であることをご了承ください。エラーの原因によっては違う解決方法になることが考えられます。
結論(解決方法)
unicorn.rbの設定記述ミスです。以下の通り変更しました。
開発中のアプリのパスが違うために、unicorn.pidを作成する/var/www/badsuru/current/shared/tmp/pids/ディレクトリが見つからず、タイトルのエラーを吐き出していました。変更前
unicorn.rb//サーバ上でのアプリケーションコードが設置されているディレクトリを変数に入れておく app_path = File.expand_path('../../', __FILE__) //アプリケーションサーバの性能を決定する worker_processes 1 // アプリケーションの設置されているディレクトリを指定 working_directory app_path (以下省略)変更後
unicorn.rb//サーバ上でのアプリケーションコードが設置されているディレクトリを変数に入れておく app_path = File.expand_path('../../../', __FILE__) //アプリケーションサーバの性能を決定する worker_processes 1 // アプリケーションの設置されているディレクトリを指定 // currentを指定 working_directory "#{app_path}/current" (以下省略)詳細
Capistarnoの自動設定ファイルを記述し、いざ実行したところ、以下のエラーが吐き出されました。
00:44 unicorn:start 01 $HOME/.rbenv/bin/rbenv exec bundle exec unicorn -c /var/www/myapp/current/config/unicorn.rb -E deployment -D 01 bundler: failed to load command: unicorn (/var/www/myapp/shared/bundle/ruby/2.7.0/bin/unicorn) 01 ArgumentError: directory for pid=/var/www/myapp/current/shared/tmp/pids/unicorn.pid not writable 01 /var/www/myapp/shared/bundle/ruby/2.7.0/gems/unicorn-5.4.1/lib/unicorn/configurator.rb:100:in `block in reload' 01 /var/www/myapp/shared/bundle/ruby/2.7.0/gems/unicorn-5.4.1/lib/unicorn/configurator.rb:96:in `each' 01 /var/www/myapp/shared/bundle/ruby/2.7.0/gems/unicorn-5.4.1/lib/unicorn/configurator.rb:96:in `reload' 01 /var/www/myapp/shared/bundle/ruby/2.7.0/gems/unicorn-5.4.1/lib/unicorn/configurator.rb:77:in `initialize' 01 /var/www/myapp/shared/bundle/ruby/2.7.0/gems/unicorn-5.4.1/lib/unicorn/http_server.rb:77:in `new' 01 /var/www/myapp/shared/bundle/ruby/2.7.0/gems/unicorn-5.4.1/lib/unicorn/http_server.rb:77:in `initialize' 01 /var/www/myapp/shared/bundle/ruby/2.7.0/gems/unicorn-5.4.1/bin/unicorn:126:in `new' 01 /var/www/myapp/shared/bundle/ruby/2.7.0/gems/unicorn-5.4.1/bin/unicorn:126:in `<top (required)>' 01 /var/www/myapp/shared/bundle/ruby/2.7.0/bin/unicorn:23:in `load' 01 /var/www/myapp/shared/bundle/ruby/2.7.0/bin/unicorn:23:in `<top (required)>' 01 master failed to start, check stderr log for details (省略)当初、
unicorn.pid not writable
と記述があったので、権限周りのエラーかと思い、releases,current,shared...などなど様々なディレクトリに書き込み権限を与えても解決されず、途方にくれていました。また、
mkdir pids
コマンド等で予めディレクトリを作成しなければならないという情報をググって見つけて試したけど上手く行かず・・・
見直したつもりの設定ファイルの記述を丁寧に見直したら結論の間違えに気が付きました。推測になってしまいますが、unicornの起動と共にunicorn.pidsファイルを設定ディレクトリ配下に作成するのですが、unicornを実行させるアプリケーションのディレクトリ設定が間違えている状態です。unicorn.pidsファイルを作成したいのだけど、そのディレクトリにも辿りつけないから、見つからないというメッセージの代わりに、タイトルのエラーが吐き出されるようです。確かに、エラーの解決法を探している時も、設定ファイルの記述を指摘する記事もあったなあ・・・
終わりに
エラーが出て、指摘通りの内容を修正してもまだ出る時は、エラー文と違うミスの可能性も十分に考えられること。自分が記述してきたファイルをしっかり見直ししようという教訓になりました。