続) GitHub Actionsの何か

はじめに

昨年末に実家が空き巣に入られたり、年始早々身体に異変があってメンタル的に疲れているところに自分史上間違えなく上位に入る節々の痛さと突発的高熱、その翌週には、首を盛大に寝違えてキョンシーみたいな姿勢での生活を余儀なくされました。どうも僕です。

ちなみに巷で流行っているコロナではなく、ただの風邪で2日半くらいで回復して味覚等々を失うことなく今は、元気に業務と麻雀に励んでいます。

前回のブログ

  • GitHub Actionsのcronがあるらしいってことでそれを使ってアニメの放送日にSlackへ通知しようぜ!ってのをやりました。

あれから一ヶ月

  • おかげさまでアニメを見逃す日がなくなりました!(素晴らしい)

改善点と改善案

GitHub Actionsのcronラグあり過ぎじゃね?問題

  • こちらは、無料枠で無料でGiHub様の善意の元リソースを使わせていただいているのでちょっと文句言いたいけどスルーすることにしました
    • ただ何かしらのプロダクトには、活用場面なさそうって思いました。

Jsonデータで管理するのだるい問題

  • 前回の目的は、見たいアニメの放送を見逃さない。っていう点にしか焦点は当たっておらずデータの収集や管理に関しては、全くの無関心でした
  • なので改善点としては、以下になると思います。
    • JsonデータのGitHub以外での管理
    • Jsonデータを自動で作成する

改善点挙げておいてなんですが何かと初物や久々(何かを)に触るのがいいと思っていますので、遠い昔に触ったFirebaseでJsonを管理しようかなと考えたんですがクレデンシャルをどう管理すんねんS3か?って考えたんですがこのプロジェクトは、すべてを無料で!を心がけているので却下です。(微々たる金額で済むのも想定できるんですがね)

今回の実装

スクレイピングJsonデータ作るぞの巻きに決定しました。

やらないこと

前提

import requests
from bs4 import BeautifulSoup
from os import getenv
import json
import datetime as dt
import calendar

today = dt.date.today()
dayName = calendar.day_name[today.weekday()]

if today.month < 10:
    month = f'0{today.month}'
else:
    month = today.month

weekList = {
    '月': 'Monday',
    '火': 'Tuesday',
    '水': 'Wednesday',
    '木': 'Thursday',
    '金': 'Friday',
    '土': 'Saturday',
    '日': 'Sunday'
}

load_url = getenv('SCRAPING_TARGET_URL')
html = requests.get(load_url)
soup = BeautifulSoup(html.content, "html.parser")

animeList = soup.find(class_='week_area').find_all('li')

jsonList = []
for e in soup.find(class_='week_area').find_all('li'):
    week = weekList[e.find(class_="oatime").find(class_='youbi').text]
    e.find(class_="oatime").find(class_='youbi').decompose()
    e.find('h4').find('strong').decompose()

    item = {
        'title': e.find('h4').text,
        'publish_at': e.find(class_="oatime").text,
        'channel': 'TOKYO MX',
        'day_of_week': week
    }
    jsonList.append(item)


with open(f'./data/anime/{today.year}{month}.json', 'w') as f:
    json.dump(jsonList, f, ensure_ascii=False, indent=4)

前回同様解説していきます

コードを読めばわかるって内容なので解説すべきことはないんですけどね!   スクレイピングしたあとのDOM操作に関しては、ほんと愚直な方法しか思いつかなかったので誰かいい方法があったら教えて欲しいです

  - あーどうしよっておもったDOM操作が下記のようなHTMLでした

<div class="oatime"><p class="youbi"></p>25:05~ </div>
  • こんな形のHTMLだとclass="oatime"直下のテキストを抜くと25:05〜が改行付きで取得できてしまう。なので先に曜日だけ取得して曜日のクラスのDOMを削除して時刻の取得を行うってことをしました。
    • 下記のような処理
week = weekList[e.find(class_="oatime").find(class_='youbi').text]
e.find(class_="oatime").find(class_='youbi').decompose()

さきに最終的なJsonファイルをどうぞ

[
    {
        "title": "\n7SEEDS\n",
        "publish_at": "22:30~ ",
        "channel": "TOKYO MX",
        "day_of_week": "Monday"
    },
    {
        "title": "\nたとえばラストダンジョン前の村の少年が序盤の街で暮らすような物語\n",
        "publish_at": "23:00~ ",
        "channel": "TOKYO MX",
        "day_of_week": "Monday"
    },
   ......
]
  • 最終的に前回手動で作成したJsonファイルと同じような形式をとることにしました。(処理をわざわざ変えるのもなーっておもったので)
    • ファイル名に関しては、前回ファイル名を取得する際の方法で生成したyyyymmの形式にしました。

新たな問題点

  • TOKYO MXしか見ねー的なノリで始めたんですが、推しキャラなの二乃がいる五等分の花嫁約束のネバーランドがT◯Sやフ◯TVじゃないですか。
  • これに関しては、それ以外の取得に関して考えて、結果マージしたデータでSlackに飛ばすようにするんだろうなってうっすら考えてます。まぁどちらもアマプラでいつでも見れるんですけどね!

  • いつcronで動かすよ問題!

    • 日次で動かす内容ではないし、月1でも違うし、1クール単位がいいんですがー言うてそんな設定できるんか?基準日を考慮できないと思うのでn日毎には実行難しそう。
    • ってことでこちらは、おそらくPython側で判定する形にするでしょう!月1実行とかにして。

反省

Pythonのお作法わからずだぁーって書いてしまっているので、リファクタリングとmodule化等を行っていきたいと思います。年末年始、特に年末が何してたかわからんくらいな状態だったので何もできなかったのでこれから平日含め学習をする癖がつくことただただ願います。

最後に独り言

アニメの通知ってamebaTVでできません?やアルっていう漫画サービスで発売日通知できますよって会社の同僚に言われました。「そそそそそうだったの」って内心では、思ったのは、内緒です。

GitHub ActionsにCronがあると聞いたんだ

はじめに

腹筋ローラーを初めて以降、筋肉痛なのか、姿勢の悪さからのコリなのかわからない苦しみが起きています。

あとウォーキングデットやゴールデンカムイを見ていついかなる状況になっても生存しなくてはいけないと感じてキャンプに興味を持ちました。

さて今回の目的

GitHub ActionsのCronで何すっかって話なのですが

最近に限ったことではなくて、僕は、数字の4桁以上を覚えるのがなかなか苦手なレベルの脳内メモリ所有者なのですが

来期のアニメの見なくてはいけないタイトルが10タイトルくらいあり、放送日時を把握し切れる訳がないじゃないか!って危機的状況に陥っている訳です。

仮にリアタイで見れなくてもアマプラさんで解決する部分もあったり絶命するわけではないのですが、個人的にHPが2割以下くらいになって日々のモチベーションがダダ下がりするのだろうと想定されるのです。

なのでよしGitHub Actionsの学習がてら毎朝か業後くらいの時間に通知行くようにしようぜ!

なんならPythonでやってみようぜ!

って昨日の夜中に思い立ったのでやってみたいとおもいます。

補足

我が家は、録画機能を有した何かしらの文明機器を持ち合わせていません。

前提

ゴール

最終的に以下のようにslackへ放送日に通知が行くようにします。 f:id:hironekosun:20201223154138p:plain

実装:Python

コードを先に晒します。

import json
import slackweb
from os import getenv
import datetime as dt
import calendar

today = dt.date.today()
dayName = calendar.day_name[today.weekday()]

if today.month < 10:
    month = f'0{today.month}'
else:
    month = today.month

data = json.load(open(f'./data/anime/{today.year}{month}.json', 'r'))

slack = slackweb.Slack(url=getenv('SLACK_WEBHOOK_URL'))

for v in data:
    if v['day_of_week'] == dayName:
        attachments = [
           {
               "fallback": 'アニメの放送時間のご案内',
               "pretext": '本日放送のアニメ',
               "fields": [
                   {
                       "title": 'タイトル',
                       "value": v['title'],
                   },
                   {
                       "title": '放送時間',
                       "value": v['publish_at'],
                       "short": "true"
                   },
                   {
                       "title": 'チャンネル',
                       "value": v['channel'],
                       "short": "true"
                   }
               ]
           } 
        ]
        slack.notify(attachments=attachments)

解説

  • 特別語ることは少ないです。

  • slackweb

こちらのライブラリが一番手っ取り早く簡単そうだったので使いました。

所感としては、ほんと単純なコードで通知することが可能なので誰でも迷わず実装が行えると思います。

  • getenv

getenvを使用して環境変数を取得してslackのweb hook urlをコードにハードコードしないようにします。

  • 全体

読めばわかるとは思うのですが、予めJSONのfileにデータを入れておきそのデータを元に今日放送をするアニメかどうかを判定して通知を行っています。

.
├── attachments.json
├── data
│   └── anime
│      ├── 202001.json
│      └── 202012.json
├── read.py
└── requirements.txt
  • JSON 下記の形式で通知対象にしたい情報を入れておきます(ここはスクレイピングでどうにかしたい)

file名は、必ずyyyymm.jsonとします。

[
    {
        "title": "転生したらスライムだった件",
        "publish_at": "23:00",
        "channel": "TOKYO MX",
        "day_of_week": "Tuesday"
    },
    ....
]

実装:GitHub Actions

  • こちらも先にコードを晒します。
on: 
  schedule:
    - cron: '55 0 * * *'

jobs:
  slack:
    name: Run slack
    runs-on: ubuntu-latest
    env:
      SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Set up Python 3.8
        uses: actions/setup-python@v1
        with:
          python-version: 3.8
      - name: pip install
        run: pip install -r requirements.txt
      - name: post
        run: python read.py
  • cron

注意点として5分以下は動かないっぽいのとdefault branch以外は、cronの対象にならないとのこと

またこのcronが結構いい加減なので5分くらいのズレは、デフォです。

なので今回実行時間を10時に実行されるといいなーって気持ちでUTC 00:55 = 日本時刻 09:55 に設定しました。

GitHub Actionsよろしく!

  • secrets

今回slackのweb hook urlを使いますのでコードにハードコードしたくなく、外に晒すのもなーっていう気持ちなのでGitHubの機能を使用しました

Settings > Secretsで設定ページへ遷移します。New repository secretボタンを押下し追加します。

使い方は${{ secrets.KEY_NAME }}となります。

今後

漫画やアニメが好きなんですが既存の世に出ているサービスでは、僕のやってほしいことを満たすサービスが1mmもないのでこれを気に作ってやるんだから!って気持ちがふつふつと湧いてきました。

年末年始、時間があるようでないようなものですが積読している書籍読みつつ、開発していきたいなって気持ちです。

最後に独り言

グーカレでよくね?という意見は、受け付けますん。すみませんブログネタ考えたあとに振り返ったらグーカレの定期でよくねって考えに至りました。

Next.js + TS + Tailwindで入門してみる

はじめに

最近腹筋ローラーを買って速攻で筋肉痛になりました。The walking deadもやっとシーズン10まで見終わりそうです。

なぜNext.jsを触るのか?

在籍している会社にてNext.jsを使用する流れになり、入門はしたけども忘れてしまったから再度入門して肩慣らしでもしておこう!という気持ちになり、今回触ることにしました。 TSにしているのは、会社ではTSで実装しているため多少いじるにしてもTSの方がいいでしょう!という理由です。

Next.js

nextjs.org

Nuxt.jsより以前から開発が行われているReactのフレームワークです。

公式に物凄い数のexampleが用意されています。

github.com

ゴール

今回は、Next.jsを開発しているVercel社が用意しているサンプルにTailwindを適用してみるの巻です。

参照

kakakakakku.hatenablog.com

今回は、参照記事を元に公式が用意しているexampleのwith-typescriptを使用してみたいとおもいます。

準備

  • nodeのversionは、v14.15.1を使用します。
mkdir next-ts-sample
cd next-ts-sample
npx create-next-app --example with-typescript .
  • installが終わったのでyarn devを実行してみる。下記画像のような表示がされました。

f:id:hironekosun:20201209140713p:plain

  • Next.jsのアプリ全ページにTailwindを使えるようにするためにpages以下に下記fileを作成します。
    • ComponentなどをLayoutなどでラップしてあげるといいです
import './styles/tailwind.css'

function App({ Component, pageProps }) {
    return <Component {...pageProps} />
}

export default App

Tailwind入れる

yarn add -D tailwindcss@latest postcss@latest autoprefixer@latest
npx tailwindcss init --full
touch pages/styles/tailwind.css
  • 作成したtailwind.cssに以下を追加します
@tailwind base;
@tailwind components;
@tailwind utilities;

tailwind.config.jsに追記

  • Purge オプションを使ってビルドサイズの縮小するこができます。
const colors = require('tailwindcss/colors')

module.exports = {
  purge: ['./components/**/*.jsx', './pages/**/*.jsx']

// 省略

postcss.config.jsの作成

module.exports = {
  plugins: ['tailwindcss', 'autoprefixer'],
}

ブラウザで一度確認してみる

  • さきほどまでと様子が違うのでtailwindがあたってそうですね。

f:id:hironekosun:20201209154509p:plain

Tailwindを感じてみよう!

  • pages以下にweather.tsxを作成し以下を記述する
const Weather = () => (
    <div className="min-h-screen flex items-center justify-center">
        <div className="border-solid border-2 flex flex-col bg-white rounded p-4 w-full max-w-xs">
            <div className="font-bold text-xl">Sydney</div>
            <div className="text-sm text-gray-500">Thursday 10 May 2020</div>
            <div className="mt-6 text-6xl self-center inline-flex items-center justify-center rounded-lg text-indigo-400 h-24 w-24">
                <svg className="w-32 h-32" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 15a4 4 0 004 4h9a5 5 0 10-.1-9.999 5.002 5.002 0 10-9.78 2.096A4.001 4.001 0 003 15z"></path></svg>
            </div>
            <div className="flex flex-row items-center justify-center mt-6">
                <div className="font-medium text-6xl">24°</div>
                <div className="flex flex-col items-center ml-6">
                    <div>Cloudy</div>
                    <div className="mt-1">
                        <span className="text-sm"><i className="far fa-long-arrow-up"></i></span>
                        <span className="text-sm font-light text-gray-500">28°C</span>
                    </div>
                    <div>
                        <span className="text-sm"><i className="far fa-long-arrow-down"></i></span>
                        <span className="text-sm font-light text-gray-500">20°C</span>
                    </div>
                </div>
            </div>
            <div className="flex flex-row justify-between mt-6">
                <div className="flex flex-col items-center">
                    <div className="font-medium text-sm">Wind</div>
                    <div className="text-sm text-gray-500">9k/h</div>
                </div>
                <div className="flex flex-col items-center">
                    <div className="font-medium text-sm">Humidity</div>
                    <div className="text-sm text-gray-500">68%</div>
                </div>
                <div className="flex flex-col items-center">
                    <div className="font-medium text-sm">Visibility</div>
                    <div className="text-sm text-gray-500">10km</div>
                </div>
            </div>
        </div>
    </div>
)

export default Weather
  • localhost:3000/weatherにアクセスする f:id:hironekosun:20201209161131p:plain

  • pages以下にcard.tsxを作成し以下を記述する

const Card = () => (
    <section className="flex flex-row flex-wrap mx-auto">
        <div
            className="transition-all duration-150 flex w-full px-4 py-6 md:w-1/2 lg:w-1/3"
        >
            <div
                className="flex flex-col items-stretch min-h-full pb-4 mb-6 transition-all duration-150 bg-white rounded-lg shadow-lg hover:shadow-2xl"
            >
                <div className="md:flex-shrink-0">
                    <img
                        src="https://www.unfe.org/wp-content/uploads/2019/04/SM-placeholder-1024x512.png"
                        alt="Blog Cover"
                        className="object-fill w-full rounded-lg rounded-b-none md:h-56"
                    />
                </div>
                <div className="flex items-center justify-between px-4 py-2 overflow-hidden">
                    <span className="text-xs font-medium text-blue-600 uppercase">
                        Web Programming
                    </span>
                    <div className="flex flex-row items-center">
                        <div
                            className="text-xs font-medium text-gray-500 flex flex-row items-center mr-2"
                        >
                            <svg
                                className="w-4 h-4 mr-1"
                                fill="none"
                                stroke="currentColor"
                                viewBox="0 0 24 24"
                                xmlns="http://www.w3.org/2000/svg"
                            >
                                <path
                                    stroke-linecap="round"
                                    stroke-linejoin="round"
                                    stroke-width="2"
                                    d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
                                ></path>
                                <path
                                    stroke-linecap="round"
                                    stroke-linejoin="round"
                                    stroke-width="2"
                                    d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"
                                ></path>
                            </svg>
                            <span>1.5k</span>
                        </div>

                        <div
                            className="text-xs font-medium text-gray-500 flex flex-row items-center mr-2"
                        >
                            <svg
                                className="w-4 h-4 mr-1"
                                fill="none"
                                stroke="currentColor"
                                viewBox="0 0 24 24"
                                xmlns="http://www.w3.org/2000/svg"
                            >
                                <path
                                    stroke-linecap="round"
                                    stroke-linejoin="round"
                                    stroke-width="2"
                                    d="M7 8h10M7 12h4m1 8l-4-4H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-3l-4 4z"
                                ></path>
                            </svg>
                            <span>25</span>
                        </div>

                        <div
                            className="text-xs font-medium text-gray-500 flex flex-row items-center"
                        >
                            <svg
                                className="w-4 h-4 mr-1"
                                fill="none"
                                stroke="currentColor"
                                viewBox="0 0 24 24"
                                xmlns="http://www.w3.org/2000/svg"
                            >
                                <path
                                    stroke-linecap="round"
                                    stroke-linejoin="round"
                                    stroke-width="2"
                                    d="M14 10h4.764a2 2 0 011.789 2.894l-3.5 7A2 2 0 0115.263 21h-4.017c-.163 0-.326-.02-.485-.06L7 20m7-10V5a2 2 0 00-2-2h-.095c-.5 0-.905.405-.905.905 0 .714-.211 1.412-.608 2.006L7 11v9m7-10h-2M7 20H5a2 2 0 01-2-2v-6a2 2 0 012-2h2.5"
                                ></path>
                            </svg>
                            <span>7</span>
                        </div>
                    </div>
                </div>
                <hr className="border-gray-300" />
                <div className="flex flex-wrap items-center flex-1 px-4 py-1 text-center mx-auto">
                    <a href="#" className="hover:underline">
                        <h2 className="text-2xl font-bold tracking-normal text-gray-800">
                            Ho to Yawn in 7 Days
                        </h2>
                    </a>
                </div>
                <hr className="border-gray-300" />
                <p
                    className="flex flex-row flex-wrap w-full px-4 py-2 overflow-hidden text-sm text-justify text-gray-700"
                >
                    Lorem ipsum dolor sit amet consectetur adipisicing elit. Alias, magni
                    fugiat, odit incidunt necessitatibus aut nesciunt exercitationem aliquam
                    id voluptatibus quisquam maiores officia sit amet accusantium aliquid
                    quo obcaecati quasi.
                </p>
                <hr className="border-gray-300" />
                <section className="px-4 py-2 mt-2">
                    <div className="flex items-center justify-between">
                        <div className="flex items-center flex-1">
                            <img
                                className="object-cover h-10 rounded-full"
                                src="https://thumbs.dreamstime.com/b/default-avatar-photo-placeholder-profile-icon-eps-file-easy-to-edit-default-avatar-photo-placeholder-profile-icon-124557887.jpg"
                                alt="Avatar"
                            />
                            <div className="flex flex-col mx-2">
                                <a href="" className="font-semibold text-gray-700 hover:underline">
                                    Fajrian Aidil Pratama
                                </a>
                                <span className="mx-1 text-xs text-gray-600">28 Sep 2020</span>
                            </div>
                        </div>
                        <p className="mt-1 text-xs text-gray-600">9 minutes read</p>
                    </div>
                </section>
            </div>
        </div>
    </section>
)

export default Card
  • localhost:3000/cardにアクセスする f:id:hironekosun:20201209161203p:plain

感想

今回のゴールがあくまでTailwindの適用なのでTSである必要なかったな

フロントのキャッチアップは、目に見えてわかるから楽しい反面、エラーが発生したりすると何を言っているんだって気持ちになるんで億劫になりがちだけど

今後も入門程度でもいいからいろいろ触って経験値だけは積んでいきたいとおもった。

あとVSCodeのフォーマッターがうまく動かず。。。

初めてAWSのLambdaを触ってみた

この記事は、最終目的に向けて複数回にわたってtryする話

最終目的

  • AWSの利用料金を毎朝Slacknに通知して請求額が跳ね上がるのを防ぎたい

なぜそんなことするのか?

  • Terraformの学習をしてた際に、applyした後にdestroyし忘れて個人としては痛い額の請求がきたからです。
    • 個人的観測範囲だと個人でのプロダクト持ってない人では、上位に食い込んでいるのでは?

今回やること

  • 今更だがLambdaに入門してSlackに通知を送ってみること

次回以降に行うこと

  • その日までの利用料金を取得しSlackに通知する
  • deploy方法
    • GithubActions or serverless
    • どちらかを使用して行えるといいなと思っています

参照

qiita.com

前提

  • AWSのアカウントを作成している人
  • Goが動く環境

実装

aws

  • アカウント作成
  • IAMロールの作成

  • aws

    • IAMでユーザーを作成している前提で話を進めます。

      コードを lambda-uploader でデプロイするためには、あらかじめ空の関数を用意する必要があります。

    • と書いてあるので予めにlambdaにて空の関数を作成します
      f:id:hironekosun:20200909160349p:plain
      create_lambda_function
      • 右上に存在している関数の作成を押下、「一から作成」を行います
      • 以下の画像のように入力し、関数の作成を押下します
        f:id:hironekosun:20200909160433p:plain
        create_lambda_function_2

        関数定義の際にポリシーテンプレートから自動作成された IAM ロールに CloudWatchReadOnlyAccess ポリシーをアタッチします。コスト情報を Lambda から読み込むのに必要です。 ロール ARN はあとで必要になるのでメモしておきます。

    • と記載があるのでこちらも対応しましょう
      • IAM > ロールで先ほど作成したロールを選択します。
      • 選択したら以下の画像のように表示されますので
        f:id:hironekosun:20200909160545p:plain
        iam_user_create
      • ポリシーをアタッチしますボタンを押下しましょう
      • 遷移後に検索窓にCloudWatchReadOnlyAccessと入れてチェックを入れて ポリシーのアタッチを行ってください。アタッチが完了したら以下の画像のようになっているはずです。
        f:id:hironekosun:20200909160608p:plain
        policy_attach
  • aws側の作業は一旦ここで終わりです。

Goで作る

package main

import (
    "encoding/json"
    "net/http"
    "net/url"

    "github.com/aws/aws-lambda-go/lambda"
    "github.com/pkg/errors"
)

type Slack struct {
    Blocks []Block `json:"blocks"`
}

type Block struct {
    Type string `json:"type"`
    Text Text `json:"text"`
}

type Text struct {
    Type string `json:"type"`
    Text string `json:"text"`
}

func run() error {
    incomingUrl := "slackのincoming hook URL"

    // slackの指定するjson形式じゃないとエラーになる
    slackMap := Slack{
        Blocks: []Block{
            Block{
                Type: "section",
                Text: Text{
                    Type: "mrkdwn",
                    Text: "検証",
                },
            },
        },
    }

    p, _ := json.Marshal(slackMap)

    resp, err := http.PostForm(
        incomingUrl,
        url.Values{"payload": {string(p)}},
    )

    if err != nil {
        return errors.WithStack(err)
    }

    defer resp.Body.Close()

    return nil

}

func main() {
    lambda.Start(run)
}
  • Goのfileをzipに固める
GOOS=linux GOARCH=amd64 go build -o main
zip handler.zip ./main
  • Go error: \$ GOPATH / go.mod exists but should not
    • このエラーが出たら自分は以下のコマンドで回避しました
export GOPATH=
  • 作成したものをawsのlambdaにアップロードしテストを実行すればslackに通知がきているかと思います

  • 今回は、ここまでとします。

何番煎じかわからないけどmacでphpenvをbuildできるようにする

phpenvのbuild errorが起きすぎる

  • macOSをCatalinaにあげたり、新規macを購入したら大抵エラーが起きたりする
  • 悲しいことに複数のprojectを抱えてたり、version固定(指定)している場合には、phpenvが必須になるので対応するしかない
    • dockerでどうこうの場合は、この限りではないと思います

前提

  • brew が入っている環境
  • anyenvでphpenvがinstall済みの環境

願い・気持ち

  • 極力zshrc等を汚したくない

結論:以下を行えば問題なくbuildができる

  • brew で必要になるものをinstallする
  • anyenv以下にあるphpenvのbuild_optionを修正する
  • phpenv install時にversionによってoptionをつけてコマンドを実行する

  • brew install

$ brew install zlib curl bzip libiconv libedit tidy-html5 openssl@1.1 icu4c krb5

~足りないものは適宜追加してください~

  • build option
$ vim ~/.anyenv/envs/phpenv/plugins/php-build/share/php-build/default_configure_options
--enable-sockets
--enable-exif
--with-zlib
--enable-intl
--with-kerberos
--with-openssl
--enable-soap
--enable-xmlreader
--with-xsl
--enable-ftp
--enable-cgi
--with-curl=/usr
--with-tidy
--with-xmlrpc
--enable-sysvsem
--enable-sysvshm
--enable-shmop
--with-mysqli=mysqlnd
--with-pdo-mysql=mysqlnd
--with-pdo-sqlite
--enable-pcntl
--with-readline
--enable-mbstring
--disable-debug
--enable-fpm
--enable-bcmath
--enable-phpdbg

# 以下を追加
--with-zlib-dir=/usr/local/opt/zlib
--with-bz2=/usr/local/opt/bzip2
--with-iconv=/usr/local/opt/libiconv
--with-libedit=/usr/local/opt/libedit
--with-curl=/usr/local/opt/curl
--with-tidy=/usr/local/opt/tidy-html5
  • php / 7.2.xのinstall
$ PHP_BUILD_CONFIGURE_OPTS="--with-libedit=$(brew --prefix libedit)" phpenv install 7.2.32

7.4.xのinstall

  • zshrcなどに以下を追記
export PKG_CONFIG_PATH="$(brew --prefix krb5)/lib/pkgconfig:$PKG_CONFIG_PATH"
export PKG_CONFIG_PATH="$(brew --prefix openssl@1.1)/lib/pkgconfig:$PKG_CONFIG_PATH"
export PKG_CONFIG_PATH="$(brew --prefix icu4c)/lib/pkgconfig:$PKG_CONFIG_PATH"
$ phpenv install 7.4.x

終わりに

  • qiitaや個人ブログで色々とありますが、みんな苦労しているんだろうなって印象です。
  • 個人的にdockerではなくmacにてphpenvでversion切り替えを行う理由は、mac側からphpコマンドを使いたい場合があるためです。なにかと都合がいいです。

Terraform入門

はじめに

  • 僕は、Terraformを実務で触ったことがありませんでした。また個人的な学習でも何から触っていいかもわからんしまぁひとまずなんかインフラをコードでどうこうできるんしょくらいの認識でいました。

  • 本記事では、書籍に沿って行った学習過程で書籍に記載がない点と「ん?」ってなった点を取り上げたいと思います。

    • 書籍詳細に関しては、省きます。

教材

  • 同僚の方にお勧めいただいたこちらを使用して学習を始めることにしました。

amzn.to

学習方法

  • 基本的には、書籍の内容に沿ってハンズオンしながら理解を進めていけたらなと思ってます。

書籍の中身

  • 前提としてAWSを題材にした書籍になってます。また目次をみていただければ記載あるのでご覧ください。
  • 個人的にいいなって思っているのはサンプルコードが200以上ある点です。

Terraformとは?

  • 下記記事を参考にしてください。

10分で理解するTerraform - Qiita

AWSでTerraformに入門 | Developers.IO

今回ハンズオンで行ったこと

  • 上記に記載しているQiitaの記事と似通っていますが以下を学習しました。

  • AWS

    • AMI
    • IAM
    • EC2
  • Terraform

    • plan
    • apply
    • destroy

学習の流れ

  • 学習の流れは、EC2インスタンをTrraformで作成し、更新を行い、またmust be replacedと表示されるような変更を行い最後にリソースの削除を行いました。
    • コード、書籍の手順等は、割愛します。

学習の際に困った点

1. 書籍の第1章セットアップでは、いきなりIAMの作成から始まってますが指示通り作成します。

日を跨いで学習を行う場合やターミナルを別タブで行う場合があまり想定されていません、環境変数の設定で使用するシークレットアクセスキーに関しては、IAM作成時にコピーして控えておいた方がいいです。 もし忘れてしまったりメモし忘れてしまった場合、下記画像を参考に新たにシークレットアクセスキーの作成を行えば再度取得ができます。(僕はこの方法しかたどり着けなかったので他に方法があるなら知りたいです!!)

f:id:hironekosun:20200718192501p:plain

  • ターミナル上で入手したアクセスIDとシークレットアクセスキーを環境変数に設定します。これで書籍の指示通りにAWSアカウントIDが出力されます。
2. 書籍に記載ないけど.....
「第2章」でAMIの使用が前提になっており肝心のAMIの作成に関してが記載ありません。作成手順がないのでAWS初心者にとっては、なんのことよ!!!!ってなると思います。

*ここでAMIの詳細については、割愛させていただきます。

AWSが公開しているAMIを使用します

参考にした記事:CloudFormationで最新のAmazon Linux 2のAMI IDを取得してEC2を構築する | Developers.IO

  • 参考記事で紹介されているコマンドを使用したいと思います。

    • 今回は、amazon linuxのAMIの使用を想定しています。
  • コマンドを実行するとAMI IDが出力されますのでそれを使用しましょう。

$ aws ssm get-parameter \
        --name /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-arm64-gp2 \
        --query "Parameter.Value" \
        --region ap-northeast-1 
 "ami-06ad9296e6cf1e3cf"

これで書籍のハンズオンが進められるようになります。

学習をしてみて

  • 大きな障害もなく終えれてよかったです。入門内容から触ってみて実際に実務で触った内容の理解が進んだり、自分の手でインスタンスが作成されたぜやっほいって気持ちとかを感じレたりしたのでハンズオン形式での学習は大事だなって改めて思いました。

  • 次は、第3章からですが内容を読むと第5章までは一気に進められる内容になっているので頑張ろうと思います。またこれを期にAWSに関しての知識も実践で使えるものに変換できていけたらならと個人的には思っています。

最後に

  • 今回、在籍する会社のCTOにAMIを作成しなくても学習できるとアドバイスをいただきました。当初公開した際の記事では、下記に示すように自分でAMIを作成する手順で書籍の内容を進めてましたがAWSが提供しているAMIを使用する手順へ変更しました。ご興味ある方は、下記手順でオリジナルのAMIを作成することが可能なので、tryしてみてください。

  • また今回記載している内容は、2020/07/21現在で動作確認が取れた内容となっています。

修正前の内容は以下です。

自身で作成する
  • AMIを作成する

    • 手順はすごく簡単です。適当に無料枠対象のEC2インスタンスを作成します。
    • 作成されたEC2インスタンスを元にAMIの作成を行います。
      f:id:hironekosun:20200718194120p:plain
      • 上記画像のように作成ができれば作成したインスタンスを選択して右クリックから イメージ > イメージの作成 を行います。名称がわかりやすいように適宜名称をつけておきましょう。
  • AMIのIDを取得

    • こちらは左にあるメニューからAMIを選択し上記で作成したAMIのIDをコピーします。
早速手順に従いterraform applyを行いインスタンスを作成するぞーって気持ちをいきなり砕きます
Error: Error launching source instance: InvalidAMIID.NotFound: The image id '[ami-id]' does not exist
    status code: 400, request id: request_id(英数字が並んでいる)
  • 何が原因か?
    • 環境変数AWS_DEFAULT_REGION東京リージョンに設定していたからです。
    • おまえ東京なんだからあってんだろって初心者の方なら思うかもしれませんが、AWSってそもそも何も考えず何も気にせずに上記のEC2インスタンスの作成を行うと、リージョンが東京ではありません。
    • なので環境変数の変更が必要です。適宜自分の環境にあった環境変数に変更しましょう。

オハイオに設定するなら下記をターミナル上で実行すればOKです。

$ export AWS_DEFAULT_REGION=us-east-2

ターミナルのshellの読み込みが遅い

タイトルの通り

  • 個人的にあまり気にしてなかったけどやたら遅かった

やったこと

  • preztoを排除
  • anyenv をrehashを都度行わないように変更

結果

  • めっちゃ早くなった(それでも遅いとは思う)

記述

  • 僕は、zshを使用しているので以下を.zshrc に追加しました。
eval "$(anyenv init - --no-rehash)"

蛇足

  • 今回preztoを排除し新たにstarshipというのを採用しました。

starship.rs

まとめ

  • こちらからは以上です