Afternoon Log

日々のことや、技術的な備忘録を吐き出していくつもり

常時SSL化対応

こんにちはこんばんは、おはようございます。

自分のwebページをHTTPS対応致しました。
SSL証明書の種類にはDV(Domain Validation)、OV(Organization Validation)、EV(Extended Validation)の3種類ありますが、
個人ですし最初のドメイン認証証明書にします。
ところで、Validationは検証の意味合いだと思っているのですけど認証って言っちゃって良いんです?

閑話休題

認証局はどこ使うかですが、流行のLet's Encryptを利用します。
無料で楽に取得できますし、自動更新スクリプトを組むこともできますからね。
結果、この先色々と大変ではあったんだけどね……。
なので、章立てしながら進めていきます。

構成

まずWebページですが、ECSを利用していてコンテナ内に静的ファイルを配置してnginxで配信しています。
最初に考えたのは、アプリケーション前にロードバランサなどを配置してそこをSSL終端にすることです。
疎結合なアプリケーションを考えると、アプリケーション自体とSSLは分離して置いた方が良いですからね。
なのでAWSにあるALB(Application Load Balancer)の導入を考えたのですが、月に2,000円ほどしそうでした。
高い。
流石に1コンテナでバランシングする必要もないアプリケーションでこれは高すぎる……。
SSL終端をLBに持ってくるのは諦めよう。
と言うわけでWebアプリケーションをSSL終端にします。
nginxとアプリケーション自体を分離するのも全然ありなのですが、まずは分離する前に目標を達成することを優先します。

証明書取得の自動化

方針が決まったので早速実装していきます。
ファイルを次の様に更新します。

Dockerfile

FROM node:12.18.4-buster

# install nginx
RUN curl -fsSL https://nginx.org/keys/nginx_signing.key | apt-key add -
RUN echo 'deb http://nginx.org/packages/debian/ stretch nginx\n\
deb-src http://nginx.org/packages/debian/ stretch nginx' > /etc/apt/sources.list.d/nginx.list
- RUN apt update && apt remove -y nginx && apt install -y nginx && apt clean
+ RUN apt update && apt remove -y nginx && apt install -y nginx openssl certbot && apt clean

COPY ./file/mu-web.conf /etc/nginx/conf.d/

# start next
# ENV NODE_ENV=production
WORKDIR /var/www
COPY ./app app/
RUN cd app && npm install && npm run export

EXPOSE 80

- CMD /usr/sbin/nginx -g "daemon off;"
+ COPY run.sh /etc/nginx/run.sh
+ RUN chmod +x /etc/nginx/run.sh
+ CMD /etc/nginx/run.sh

opensslは自己証明書のため、
certbotはLet's Encryptによる証明書取得のためにインストールします。
後半の変更は、証明書取得のコマンドを叩きたいのでシェルスクリプトにまとめただけです。

run.sh

#!/bin/bash

DOMAIN="mu-elma.net"
CERT_DIR="/etc/letsencrypt/live"

if [ ! -d "${CERT_DIR}/${DOMAIN}" ]; then
  mkdir -p "${CERT_DIR}/${DOMAIN}"
  openssl req -new -newkey rsa:2048 -sha256 -x509 -nodes \
    -set_serial 1 \
    -subj "/C=JP/ST=Tokyo/L=null/O=null/OU=null/CN=${DOMAIN}" \
    -out "${CERT_DIR}/${DOMAIN}/fullchain.pem" \
    -keyout "${CERT_DIR}/${DOMAIN}/privkey.pem"
  chmod 400 "${CERT_DIR}/${DOMAIN}/privkey.pem"
fi
nginx

if [ ${RUN_ENV} = "production" ]; then
  rm -rf "${CERT_DIR}/${DOMAIN}"
  certbot certonly -n --keep-until-expiring --agree-tos \
    --webroot --webroot-path /var/www/app \
    -m ${MAIL_ADDRESS} -d ${DOMAIN}
  nginx -s reload
fi

while true
do
    sleep 10
done

このシェルスクリプトは大きく3つの処理に分類されていています。
まずは自己証明書の準備です。
なぜ自己証明書が必要なのかというと、certbotによる証明書取得を成功させるためです。
certbotによる証明書取得の仕組みは調べて貰うと分かるのですが、
簡単に言うとhttpでアクセスできる箇所にドメイン認証用のファイルを配置し、それを確認することで証明書が発行されます。
つまり、その時点ではnginxによってアプリケーションが起動していないといけません。
コンテナを最初に起動した時はまだ証明書を取得していないので、nginxが証明書を見つけられずに起動失敗したはずです。
その失敗を回避するために、nginxの起動の前に自己証明書を発行しています。

次に、certbotによる証明書発行です。
環境変数を用いて、発行できる条件を制限しています。(環境変数名はちょっと微妙かも)
これはdocker buildした時に証明書を取りに行かないようにするためです。
たしかbuildしたときにもコマンドが実行される認識なんですが、
buildする環境はローカルだったりCircleCIだったりするので、この時点ではコンテナとドメインが結びつかず失敗すると思っています。
その後、自己証明書を削除します。
certbotで上書きしてくれるかなと思っていたのですが、上書きされなかったのでちゃんと消します。
証明書ができたらreloadします。

最後に無限ループの設置です。
今までnginxをフォアグランド実行でコンテナを終了させないようにしていました。
それが今回シェルスクリプトに格納したので、同様にできなかったんですよね。
最後にバックグラウンドからフォアグランドに持ってきたらうまく行くのかもしれないですが、
無限ループの設置しちゃった方が楽なのでこっちを選択しました。

.conf

server {
  listen 80;
  server_name mu-elma.net;
+   root /var/www/app;
+   index index.html;
+
+   location ^~ /.well-known/acme-challenge {
+     default_type "text/plain";
+     try_files $uri =404;
+   }
+ }
+ 
+ server {
+   listen 443;
+   server_name mu-elma.net;
+   ssl on;
+   ssl_certificate /etc/letsencrypt/live/mu-elma.net/fullchain.pem;
+   ssl_certificate_key /etc/letsencrypt/live/mu-elma.net/privkey.pem;

  root /var/www/app/out;
  index index.html;

  location / {
    try_files $uri $uri/index.html $uri.html =404;
    expires -1;
  }
}

80ポートで動かしている内容をまずは443ポートに切り替えます。
そこに証明書のPATHを指定します。
次に、80番ポートでcertbot用のエントリポイントを準備してあげます。
認証用以外は不要なので404を返します。
今回は後日実装という形にしたのですが、80番の他のアクセスを443へリダイレクトさせた方が良いですね。

.circleci/composition.yml

version: "3"
services:
  mu-web-service:
    image: ${DOCKER_IMAGE}
    ports:
      - "80:80"
+          - "443:443"
+      environment:
+          RUN_ENV: "production"

dockerを動かす時に443でも受け付けてくれるように更新します。
このファイルはECSでサービスを動かすときに利用しているdocekr-composeのファイルです。
序でに環境変数もセットしちゃいます。
これは先述した、docker run したときに証明書を取得できるようにするためのものです。

デプロイ完了したら、AWSのセキュリティグループで443を開けてあげます。
そしてHTTPSでアクセスできることを確認します。

f:id:mura_elma:20210214183243p:plain

……やった。やったぜ。

以上で大まかな設定はできました。
後は、色々と追加で設定したことを記載します。

Appendix 1. 秘密情報の用意

コードの中に{MAIL_ADDRESS}があったと思います。
gitでコード管理しているので、メールアドレスを記載したくなかったんですよね。
そのためメールアドレスを秘密情報として利用できるようにします。
まずAWS System Managerからパラメータストアで秘密情報を登録します。
「安全な文字列」「現在のアカウント」でメールアドレスを登録します。
次はこれを利用する側の設定を行います。
ECSから秘密情報を取得するためには、ssm:GetParametersの権限が必要なのですが、
それをタスク実行ロールに与える必要があります。
自分はタスク実行ロールを用意していなかったので、まずはこのタスク実行ロールを用意します。

docs.aws.amazon.com

作成できたら、IAMのロールから作成したecsTaskExecutionRoleを選択します。
権限とロールを紐付けるのはポリシーなのですが、わざわざこれのためにポリシー作るのもちょっと面倒だったので
今回はインラインポリシーを利用して紐付けを行います。
他にも、ecsコマンドを実行しているユーザーはタスク実行ロールではないので、
ユーザーからIAMロールへECSを利用できるようにiam:PassRoleの権限をユーザーに割り当てているポリシーに追加します。
AWSでの設定が終わったらタスク定義に反映します。

.circleci/ecs-params.yml

version: 1
task_definition:
+  task_execution_role: ecsTaskExecutionRole
  services:
    mu-web-service:
      mem_limit: 524288000 # 500MB
      mem_reservation: 262144000 # 250MB
+      secrets:
+          - value_from: mu-developer-mail
+             name: MAIL_ADDRESS

タスク実行ロールには、先ほど作ったIAMロールの名前を。secretsには利用する秘密情報を記述します。
value_fromにはSystem Manager上で登録した名前、nameには値を入れる環境変数名を指定します。
無事に利用できていたら、ECSのタスク定義から環境変数を見ることができます。

Appendix 2. AWS CLI の更新

最初にパイプラインを回した時、pipのインストールが失敗しました。

#!/bin/bash -eo pipefail
curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py"
sudo python get-pip.py
sudo apt install python-dev
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 1884k  100 1884k    0     0  23.2M      0 --:--:-- --:--:-- --:--:-- 23.2M
Traceback (most recent call last):
  File "get-pip.py", line 24244, in <module>
    main()
  File "get-pip.py", line 199, in main
    bootstrap(tmpdir=tmpdir)
  File "get-pip.py", line 82, in bootstrap
    from pip._internal.cli.main import main as pip_entry_point
  File "/tmp/tmpyQDl6R/pip.zip/pip/_internal/cli/main.py", line 60
    sys.stderr.write(f"ERROR: {exc}")
                                   ^
SyntaxError: invalid syntax

Exited with code exit status 1
CircleCI received exit code 1

どうやら pipのインストールがpython 3.6以上じゃないといけないようになった感じでした。
3.6以上じゃないの……?という疑問はありますが、なんとかせねばなりません。
しかし、pythonのバージョンアップをやるのは絶対大変だと思って調べていると、
どうやらAWS CLIのバージョンが1系のままで、今は2系があるとのことでした。

docs.aws.amazon.com

見ると、pipの準備が不要そう。
なので、ごっそりpip準備のパイプラインは削除し、AWS CLI v2をインストールします。
すると今度は、ECRのログイン方法が変わっているとのことでした。
なので、これも次の様に書き換えました。

- run:
     name: Login ECR
     command: aws ecr get-login-password | docker login --username AWS --password-stdin ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com

感想

思った以上に、色々やる必要が出てきて大変でした。記事書くのも大変でした。
そして、今回構築して思ったのですがcertbot証明書発行のコマンドは次成功するのか?というところです。
既に発行しているじゃんって拒否られないことを祈るのみです……。
また、今回結構疲れちゃったので自動更新の仕組みまでは導入していません。
CI環境から定期実行させるだけで良いと思うので、またいずれ構築していきたいと思います。
github Action使っても良いかな?

今回のgithub
github.com

2021-01 月報

こんにちはこんばんは、おはようございます。

今年から1ヶ月毎に振り返っていこうかなーと思いました。
ブログのネタがないからね。
ただ、変に凝った振り返りをしちゃうと大変なので、結構シンプルにやっていきましょう。

やったこと 内容
webサイトデザイン更新 作業は12月実施、1/1に更新。
練習のため月で1枚頑張り始めました。
ゲーム ポケダンDXのエンドロールまでやった。
お出かけ カービィカフェにまた行って来た。
新年のちっちゃなメニューを楽しんだり、トートバッグ買って来ました。
https://twitter.com/mura40424/status/1347761834313482242

2月のやっていきたいこと

  • webサイトのHTTPS化
  • 2月の絵の練習
  • コメダのクロネージュ リッチショコラを食べる
  • ソシャゲ(ウマとブルアカが始まっちゃう
  • 積みゲー消化開始
    • しかしどのゲーム消化しよ

2月はバレンタインがあるので、チョコ系の美味しいもの楽しみですねー。
バレンタイン自体には縁はないですが、期間限定でチョコを楽しむのは好きです!
旅行や観光に関してはまだちょっと寒いのでモチベは生えていないですね。
逆にアクセスし易いお店には、ちょくちょく行きたいです。
例えば、秋葉のミリタリーショップ レプマートがめちゃんこ大きいらしいので見に行きたいです。

2021-01-01 Started

あけましておめでとうございます。

心機一転というわけではございませんが、自分のwebページを一新致しました。
更新する度に一新している気も致しますが……。

https://mu-elma.net/


今までのサイトはカードデザインを中心に構築しようとしてみたのですが、なんか微妙になってしまいました。
汚点を上げるとキリが無いですが、やはり場当たり的構築が良くなかったと思っています。
そこで今回はデザインからガッツリ考えて構築するのを目指しました。
僕自身プログラミング技術以外にもデザインに関するところも興味があったので良いきっかけでした。

続きを読む

気づいたら2020年終わりそうなんですね。

f:id:mura_elma:20201209010558j:plain

こんにちは、こんばんは、あるいは、おはようございます。
現在深夜の1時。
駄文を書き連ねるには丁度良い時間帯だと思いませんか。


気がついたらもう1年近く更新していませんでした。
さて、今日はちょっと早いですがこの一年を雑に振り返っていきたいと思います。


まず今更ではございますが、今年は随分大きな変化のある年になりました。
当然私も例に漏れず、様々な影響を受けました。
仕事面では完全フルリモートになりました。
電車通勤が消え去ったのは良いのですが、上半期の新チームとは一堂に会する機会が終ぞ訪れませんでした。
下半期にもチームが変わりはしましたが、同様にオフィスで会うということは暫く無さそうですね。
半年以上籠もっているので、オンラインベースの仕事にも慣れてきたと思います。


私生活においても、友人と外で遊ぶ機会はほぼなくなりました。
8月のお盆も帰省することもなく、年末年始も帰省できませんね。
ただ、人とは行動できない分一人でどこかに行くというのをやってみたりしました。
これは先月ではあるのですが、初頭には箱根、中旬には高尾山へと行って来ました。
真っ赤ではないのですが、どちらも素晴らしい景色を堪能させて頂きました。
来年も幾つか一人で散策しに行こうかなと考えています。
f:id:mura_elma:20201209010916j:plain
f:id:mura_elma:20201209010948j:plain


後は自分の部屋をより自分好みになるよう、少しずつ整理整頓しています。
特に来客がある訳ではないけどもウェルカムマットを導入したり、本棚を刷新したり。
オタクなのでどうしてもオシャレな部屋というのには限度はありますが、少しでも余白のある配置を目指していきたいですね。
貰った月のライト、光ってないとただのでこぼこした白い球体だし、正直邪魔なんだけどどうしよう……。


最後に創作活動とかそういう周りに関して。
MacBookProを新しくしました。ようやくシザーキーボードが復活したので。
ただ、全然開発出来ていないです。IntelliJもUltimateの方を契約したのに。
ブログも自分のサイトも全然。
ただこのままではいけないのでAdobe周りのソフトも導入して、より開発とデザインに着手していくつもりです。
絵の方は何も描いていない……と思ったのですが、一応Twitterアイコン描いてました。
当然それだけでは技術も上がるはずがなく、描けるようになるために描いていかねばなぁというお気持ち。


さてさて、こんなところでしょうか。
今日は一先ずこんなところで終わりと致しましょう。

2019振り返り

前書き

年の瀬ですね。
僕は今お気に入りの喫茶店でこの記事を書いています。
今日はこの後帰宅して大掃除っぽいのをしようかと思います。
来客駆動掃除をしていると、来客がないと部屋が汚部屋になりがち。

さて、今年初めになんか出来もしないこと書いたかもしれないので
それも交えて今年を振り返ってみようかなと思います。

1月の振り返り

mura-elma.hatenablog.com

初っぱなこんなの書いていました。

Webサイト整理

全然整理されてませんね。
CI/CD環境を用意してコンテンツに集中できる環境を整えたんですが、
僕自身コンテンツに集中していなかった。

アプリ開発

はい。来年はしない。

部屋の整理整頓

そもそも春に引っ越しをしました。
通勤における電車乗車時間をなるべく減らした方が幸せになれると思ったので。
その結果家賃が2桁万ですが……。
それでまだ部屋はまだ完成に至ってない感ありますが、
この引っ越しを契機に巨大な本棚を捨て、食器棚をキャビネットへと変え
炊飯器などの使わない家電を捨て、そして最近机を買いました。
次はベッド横のサイドテーブルなりを考えたいという状況ですね。

可視化

まず続かない。
githubを使っても、Trelloを使っても、どうにもしっくりこない。
気分で生きがちなので、自分を管理することができませんね。
自分は小さなメモをwin10のstickyで画面に置いておくのですが、
それは表示されていても読んでいるかというと微妙なのでやりたい事として残すのも微妙な感じですね。

今年の振り返り

お絵かき

私生活においてiPadを買ってお絵かきを始めました。
サイトのデザインやアイコン、あわよくば好きなキャラを描いて満足するために。
お絵かきは楽しいですけど、やはりまだ脳内でイメージ仕切れていない姿を現実へと描き起こすのは至難の業ですね。
「へただなあカイジくん…へたっぴさ…!絵がへた…」
技術というのは一朝一夕で身に付くものではないので、少しずつでも頑張って描いていきたいですね。

アウトドア

まずお盆は白山に登る予定でした。
これは天候が芳しくなかったので中止。
来年こそ行けたらよいと思います。
また行こう行こうと思って、結局高尾山も行けてないままですね。。。

旅行としては今年の親孝行的なものとして、日光へ行きました。
直前に台風の影響で路線を変えたり、寒暖差が大きくなかったのでそこまで紅くないとか、
旅館のお料理において少々気になるところがあったりと、
個人的には全て満足して貰うと言うことが叶わなかったのが少々残念でした。
あと個人的には、もうちょっと奥まで行って中禅寺湖の遊覧船に乗ったり滝を見たかったりしたので
そこはまた別に個人的に行けたらと思いますね。

お仕事

4月から9月までの半期ですが、これは自分にとって非常にプラスになったと思います。
というのも、お仕事内容ではなく環境が良かったです。
技術的に非常につよつよな人と一緒に仕事が出来て、要はコネクションができました。
またその人達やもうちょっと偉い人にもある程度信頼を得られることが出来ました。
ただ10月からのチームや仕事内容には色々不安があって、
2020年度にこの現状のままだったり、仕事もちょっと微妙な感じだと転職を真面目に視野に入れた方が良いかなと感じてます。
上の思惑というか、政治というか、そういうのに振り回されると嫌になっちゃいますよね。
何かたまにネット上でお前がその仕事をしているのはそのレベルだからだって暴論を見かけたりしますが、
適材適所が行われるなんて実は稀な環境なんじゃないかなって思うんですよね。

おっと、愚痴が広がりそうですね。

罪(積み)

おいおい、ゲーム積みがちじゃないか。
プラモデルも完成してないな?
本もどれだけ残ってる。
見たいなー見なきゃなーと言っていたアニメは?

終わり

振り返りはこんな所でしょうか。
2020年にやりたい事は2020年に考えるとしましょう。

あー、猫飼いたい……。

CircleCI からECSへ自動デプロイ

三部作の最終回。

前回ほぼほぼECRの方の話しかしてない気がする。
大事な部分、コードペタッと貼っただけじゃねーか!と言われても仕方ない。
そして残念、たぶん今回も。。。

  1. CircleCI で docker build するまで
  2. CircleCI からECRへ自動push
  3. CircleCI からECSへ自動デプロイ ← イマココ
続きを読む

CircleCI からECRへ自動push

三部作の内の第二部

あんまり覚えていないので、足りない設定とかも出てくるかも。
その時は何卒ご容赦を……。

  1. CircleCI で docker build するまで
  2. CircleCI からECRへ自動push ← イマココ
  3. CircleCI からECSへ自動デプロイ
続きを読む