kakakakakku blog

Weekly Tech Blog: Keep on Learning!

Envoy の lb_policy は ROUND_ROBIN 以外にもある!「Controlling load balancing policies」を試した

今回は「Try Envoy」「Controlling load balancing policies」を紹介する.Envoy でサポートされている「ロードバランスポリシー」の種類を学べる.ただし,Weighted round robin の動作確認は期待通りに動かず,消化不良な感じになってしまった.個人的には「Controlling load balancing policies」は実施しなくて良いと思う.可能なら Katacoda 側で内容を見直してもらえると良さそう.

Detecting Down Services with Health Checks

手順は以下の「計3種類」ある.

  • Step.1 「Load balancing policies」
  • Step.2 「Weighted round robin」
  • Step.3 「Generating Traffic」

なお,最近 Try Envoy にあるリンクは 404 エラーになってしまった(年末までは見れていた).ただ Katacoda を使えば,引き続き同じコンテンツを実施できる.

www.katacoda.com

Step.1 「Load balancing policies」

Envoy では Cluster の lb_policy「ロードバランスポリシー」を設定できる.今まで試してきた Try Envoy では,全て ROUND_ROBIN を使っていたけど,実際には多くの種類が実装されている.

  • Weighted round robin (ROUND_ROBIN)
    • デフォルト設定
  • Weighted least request (LEAST_REQUEST)
  • Ring hash (RING_HASH)
  • Random (RANDOM)
  • Original destination (ORIGINAL_DST_LB)
    • Envoy v1.12.0 から非推奨で CLUSTER_PROVIDED を使う
  • Maglev (MAGLEV)
  • Cluster Provided (CLUSTER_PROVIDED)

RING_HASH は名前の通り Consistent Hashing の実装となる.ドキュメントを読むと ketama という C で実装されたライブラリのリンクがあり,Envoy の内部で使われているとのことだった.また MAGLEV は今回はじめて知ったけど,Google から論文が出ているアルゴリズムらしく,ketama よりも高速とのこと.気になる!

github.com

「ロードバランスポリシー」の詳細は以下のドキュメントに載っている.

www.envoyproxy.io

www.envoyproxy.io

Step.2 「Weighted round robin」

envoy.yamllb_policyROUND_ROBIN を設定する.今までの Try Envoy で何度も試したため,正直言うと他のロードバランスポリシーを試したかった.なお,今回は clusters の中に hosts を設定せず,新しく load_assignment を設定していた.よくよく調べると,Envoy v1.8.0 から hosts は非推奨になり load_assignment が推奨になっていた.今までの Try Envoy は非推奨の設定を使っていたことに気付く.ううう!

www.envoyproxy.io

さらに load_assignment の挿入場所に誤りがあり,Envoy の起動時にエラーになる.正しくは clusters のパラメータなので,以下のように lb_policy と並べる必要がある.修正はプルリクエストを送っているけど,取り込まれるまでは要注意!

envoyproxy.io

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 10000 }
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          codec_type: auto
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: backend
              domains:
                - "*"
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: targetCluster
          http_filters:
          - name: envoy.router
  clusters:
  - name: targetCluster
    connect_timeout: 0.25s
    type: STRICT_DNS
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    load_assignment:
        cluster_name: targetCluster
        endpoints:
        - lb_endpoints:
            - endpoint:
                address:
                    socket_address:
                        address: 172.18.0.3
                        port_value: 80
            load_balancing_weight: 90
        - lb_endpoints:
            - endpoint:
                address:
                    socket_address:
                        address: 172.18.0.4
                        port_value: 80

そして,Envoy と katacoda/docker-http-server:healthy を起動する.

$ docker run --name=proxy -d \
  -p 80:10000 \
  -p 9901:9901 \
  -v $(pwd)/envoy/:/etc/envoy \
  envoyproxy/envoy:latest

$ docker run -d katacoda/docker-http-server:healthy;
$ docker run -d katacoda/docker-http-server:healthy;

Step.3 「Generating Traffic」

実際に while で Envoy にリクエストを送り続ける.

ドキュメントを読むと,endpoint.LocalityLbEndpointsendpoint.LbEndpoint に対する load_balancing_weight があり,混乱した.今回は前者の設定となり,172.18.0.3 側に多くのリクエストが送られるのかと予想したけど,動作確認をしてもルーティングに差は出なかった.うーん?理解が間違っている?よくわからず,もう少し Try Envoy として解説を書いて欲しいなと思う.

$ while true; do curl localhost; sleep .5; done

まとめ

  • 「Try Envoy」のコンテンツ「Controlling load balancing policies」を試した
  • Weighted round robin の動作確認は期待通りに動かず,消化不良な感じになってしまった
    • 実施しなくて良いと思う 😇

残るは1個!引き続き,進めていくぞ!

プルリクエスト

試しながら気付いた誤りを修正してプルリクエストを送っておいた!

github.com

Try Envoy 関連

2019年の振り返りと2020年の抱負

既に1月後半になり,遅くなってしまったけど,毎年恒例の「振り返りと抱負」をまとめておこうと思う.

2019年の振り返り 🎉

幅広く技術を学べた

2019年の目標は「幅広く技術を語れるように学び続ける」としていた.未経験の技術は無限にあるし,苦手意識のある技術領域もある.2019年は意図的に「幅広さ」を意識した1年だった.そして,この戦略は正解だったとも感じる.1年前と比べて「技術的な幅広さ」という観点では少なからず成長実感がある.

ブログのカテゴリを見ても,例えば「Python, React, Envoy, GraphQL, Docker, Ansible, Kubernetes, Prometheus, HashiCorp」などなど,技術領域の制限はせず,様々な技術に挑戦できた.そして幅広く学んだからこそ,さらなる「未経験の技術の発見」もできた.本当に未経験の技術は無限にある!Trello のチケットは日々増えているけど,1年間を通してずっと「楽しく学び続けられた」ことは良かった.

当然ながら「技術的な深さを追い求めること」は課題となる.認識はしている.しかし,仕事柄プロダクションコードを書く機会はないし,2018年まで3年間連続で目標にしていた「実践投入力を高める」場面もないことから,今の自分には「幅広さを追求すること」にプライオリティの高さを感じている.2020年も同じ目標を掲げる.

教える / 教える / 教える

技術講師として,1年間ずっと「教えるとは何か?」を考えていた.考えて,実践し,失敗し,改善する.そんなサイクルを繰り返し,ようやく自分のスタイルに到達できた気がする(あくまで気がする).例えば「ラーニングピラミッド」「経験学習モデル」を意識した教授戦略プランを考えたり,初学者に「どういうところに難しさを感じるか?」というヒアリングをして,初学者の域を過ぎた自分では気付けなくなった「難しさの観点」を整理してみたりもした.

また「ペアプログラミング」「モブプログラミング」のメリットを研修の場に適用し,思考の透明性を高める施策なども実践した.さらに2019年の後半3ヶ月は「テスト駆動開発 x モブプログラミング」を体験してもらう社内研修を計10回も開催した.とにかく1年間ずっと「教える」ことに没頭していたし,天職であると思う.

ブログメンタリングを継続できた

2019年もブログメンタリングを継続できた.2019年にご一緒させて頂いたメンティは「計28名(現メンティ含む)」で,累計は「計44名(現メンティ含む)」となる.冷静に考えると異常な人数規模になってきたと思うけど,「無料なの意味不明なんですけど!」という褒め言葉を頂くと嬉しくなり,まだまだ続けられそうな気がする.なお,引き続き応募倍率が高くお断りをすることもあるし,募集期間外の問い合わせも増えてきているけど,ベストエフォートで頑張っているため,お待ち頂ければなーというところ.

インプット/アウトプット 💡

登壇

2019年の登壇は計1回だった.「DevLOVE X」で登壇する機会を頂けたのは非常に嬉しかった.自分で言うのもアレだけど,参加者層のペルソナを相当考えたし,練習もしたし,鬼スベリ覚悟のギャグも投入したし,今でも発表会場の雰囲気を思い出せる.そして Togetter を見直すと今でも笑える.詳しくは以下の記事に載せてあるから是非見てもらえると!

kakakakakku.hatenablog.com

勉強会

2019年に参加した勉強会も,登壇した「DevLOVE X」1回だった.過去数年間から考えると明らかに少ないけど,2019年は「勉強会に参加する時間を他の作業時間に回す」という取捨選択を意図的にしていた.そして,もう1個の理由は「ノドのケア」で,仕事柄ノドが生命線だったりもするため「不特定多数の人が集まる場を避けていた」という背景もある(移動中も常にマスクをしている).とは言え,2020年はもう少し参加したいと考えている.

kakakakakku.hatenablog.com

プルリクエスト

2019年は計17個のプルリクエストを OSS に送ることができた.詳細は既にまとめてある.

ブログ

2019年も「週1回」のノルマを達成し「計72記事」を書いた.1年間を通して,1記事も書けなかった週はなく,確実に習慣化はできているなと再確認できた.そして「週x回」のノルマ生活は2015年から5年も続いていることになる.2019年は「幅広く技術を語れるように学び続ける」という目標もあり,すぐ忘れる自分のために書いた記事も多かったけど,累計ブクマ数は2019年で「12281 → 14771 (+2490)」という結果だった.ブクマを集めることは目的ではないけど,誰かの役に立つ記事が書けているのであれば,嬉しいなと思う.

f:id:kakku22:20200121000243p:plain

なお,200 ブクマを超えた記事は5記事だった.

kakakakakku.hatenablog.com

kakakakakku.hatenablog.com

kakakakakku.hatenablog.com

kakakakakku.hatenablog.com

kakakakakku.hatenablog.com

書籍

出版に直接携わったわけではないけど,O'Reilly Japan から春に出版された「分散システムデザインパターン」の出版レビューに参加できたことは非常に印象に残っている.今でもパラパラと読み直している.詳しくは以下の記事にまとめてある!

kakakakakku.hatenablog.com

読んだ本

2019年は「計16冊」読んだ.特に忙殺されていた月は書評記事を書けてないけど,それでも2018年よりも多く読むことができた.

Mackerel アンバサダー

光栄なことに2019年3月に「Mackerel アンバサダー」に就任させて頂いた.定量的なアウトプットの規定は(現在のところ)なく,やはり個人的にはブログに期待をして頂いているのかなと感じていたため「3ヶ月に1記事(2019年に3記事)」という目標を掲げていた.ただし,結果としては2記事で未達成となり,反省点が多くある.2020年も同じノルマ「3ヶ月に1記事」で頑張る.

2020年の抱負 ✨

幅広く技術を語れるように学び続ける

振り返りにも書いた通り,2019年に掲げた「幅広く技術を語れるように学び続ける」という目標がうまくハマったため,2020年も継続する.フロントエンド/バックエンド/インフラ/マネジメントなど,技術領域の制限はせず,好奇心のままに貪欲に学び続けていく.特に「OSS」など,オープンな技術を主軸にすることも2019年と変わらず継続する.

そして,2020年は新たに「教えてもらう」という施策にも取り組んでみたいと思う.背景としては,技術講師として「教えること」を追求しているし,その価値を実感しているのにも関わらず,自分自身は「1年間ずっと独学ばかりしていた」というギャップに悩んでいた.特に新しい技術に入門するときに独学をするのは非効率だし,誤ったベクトルに進んでしまうこともある.そして,何よりもまず「自分自身が気付いていないことは調べることすらできない」という問題があるため,積極的に「達人を味方」にして,学んでいく.教えてー!

定量的な目標は過去2年間と変わらず,以下となる.

  • ブログは変わらず「週1記事」ノルマ
  • ストレッチゴールとして年間「70記事」

まとめ

2020年も攻めていくぞ 🔥

過去の振り返り

Envoy の route.HeaderMatcher を使う「Implementing Blue / Green Rollouts」を試した

今回は「Try Envoy」「Implementing Blue / Green Rollouts」を紹介する.Envoy でサポートされている様々なルーティング設定の中から「HTTP Header ベースルーティング」「加重ラウンドロビン」を学べる.

Implementing Blue / Green Rollouts

手順は以下の「計6種類」ある.

  • Step.1 「Envoy Base Configuration」
  • Step.2 「Header-Based Routing」
  • Step.3 「Deploy Header-Based Routing」
  • Step.4 「Weighted Load Balancing」
  • Step.5 「Rollout 20% Traffic」
  • Step.6 「Rollout 100% Traffic」

www.envoyproxy.io

www.katacoda.com

Step.1 「Envoy Base Configuration」

Step.1 では envoy.yaml を読み解き,クイズに正解する必要がある.理解度確認になって非常に良いと思うし,Katacoda ってクイズ形式も作れるんだ!というプラットフォームの機能の幅広さに驚いたりもした.

  • Question: How many routes have been defined within the configuration?
  • Question: How many clusters have been defined within the configuration?

f:id:kakku22:20200112132842p:plain

Step.2 「Header-Based Routing」

ユーザーに影響を出さず,新機能をテストすることを「ダークリリース (Dark Releases)」と言う(とコンテンツに書いてある).Envoy の route_config は上から順番に比較し,最初に一致したルーティング設定を使うことになるため,今回は /service/2 に対して2種類のルーティング設定をしている.今回は HTTP Header x-canary-versionservice2a という値が設定されている場合に Cluster service2a にルーティングする.

route_config:
  virtual_hosts:
  - name: backend
    domains:
    - "*"
    routes:
    - match:
        prefix: "/service/1"
      route:
        cluster: service1
    - match:
        prefix: "/service/2"
        headers:
        - name: "x-canary-version"
          exact_match: "service2a"
      route:
        cluster: service2a
    - match:
        prefix: "/service/2"
      route:
        cluster: service2

Envoy は routes の設定として route.RouteMatch を使えば,細かくルーティングを制御できる.今回は route.HeaderMatcher を使って HTTP Header ベースのルーティングを実現している.高機能ロードバランサとして機能が揃っている!

www.envoyproxy.io

Step.3 「Deploy Header-Based Routing」

次に Envoy と katacoda/docker-http-server を起動する.katacoda/docker-http-serverv1 を2個 / v2 を2個 / v3 を1個起動する.構成図は以下のようになる.

$ docker run -d --name proxy1 -p 80:8080 -v /root/:/etc/envoy envoyproxy/envoy

$ docker run -d katacoda/docker-http-server:v1
$ docker run -d katacoda/docker-http-server:v1
$ docker run -d katacoda/docker-http-server:v2
$ docker run -d katacoda/docker-http-server:v2
$ docker run -d katacoda/docker-http-server:v3

f:id:kakku22:20200112132915p:plain

katacoda/docker-http-server とコンテナ ID の関係を整理しておくと,以下のようになる.

$ docker ps -q | xargs -n 1 docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}} {{ .Config.Hostname }} {{ .Config.Image }}' | sed 's/ \// /'
172.18.0.7 fdf5019381c2 katacoda/docker-http-server:v3
172.18.0.6 64724167bc8d katacoda/docker-http-server:v2
172.18.0.5 63a9ff40f850 katacoda/docker-http-server:v2
172.18.0.4 efab265b509a katacoda/docker-http-server:v1
172.18.0.3 c985d2391163 katacoda/docker-http-server:v1
172.18.0.2 9814e5b162f4 envoyproxy/envoy

動作確認として,まず http://localhost/service/2 にリクエストを送ると,Cluster service2 を経由して efab265b509a にルーティングされる.そして http://localhost/service/2 に HTTP Header を乗せてリクエストを送ると,Cluster service2a を経由して 63a9ff40f850 にルーティングされる.構成図の通りになっている.

# HTTP Header なし
$ curl http://localhost/service/2
<h1>This request was processed by host: efab265b509a</h1>
$ curl http://localhost/service/2
<h1>This request was processed by host: efab265b509a</h1>

# HTTP Header あり
$ curl -H "x-canary-version: service2a" http://localhost/service/2
<h1>New Release! Now v2! This request was processed by host: 63a9ff40f850</h1>
$ curl -H "x-canary-version: service2a" http://localhost/service/2
<h1>New Release! Now v2! This request was processed by host: 63a9ff40f850</h1>

Step.4 「Weighted Load Balancing」

次は「カナリアリリース」のように使える「加重ラウンドロビン」を試す.ルーティング設定に weighted_clusters を追加すると,weight に設定した割合に従ってルーティングされる.今回は /service/3 にリクエストを送ると 80% は Cluster service3a に,そして 20% は Cluster service3b にルーティングされる.

route_config:
  virtual_hosts:
  - name: backend
    domains:
    - "*"
    routes:
    - match:
        prefix: "/service/1"
      route:
        cluster: service1
    - match:
        prefix: "/service/2"
        headers:
        - name: "x-canary-version"
          exact_match: "service2a"
      route:
        cluster: service2a
    - match:
        prefix: "/service/2"
      route:
        cluster: service2
    - match:
        prefix: "/service/3"
      route:
        weighted_clusters:
          clusters:
          - name: service3a
            weight: 80
          - name: service3b
            weight: 20

Step.5 「Rollout 20% Traffic」

設定変更を反映するため Envoy を再起動する.構成図は以下のようになる.

f:id:kakku22:20200112132930p:plain

さっそく http://localhost/service/3 に対してリクエストを送ると,割合に従ってルーティングされる.繰り返し実行していると,キレイに 80% / 20% にならないこともあった.

$ for i in {1..10}; do curl -s http://localhost/service/3; done
<h1>New Release! Now v2! This request was processed by host: 64724167bc8d</h1>
<h1>New Another Release! Now v3! This request was processed by host: fdf5019381c2</h1>
<h1>New Release! Now v2! This request was processed by host: 64724167bc8d</h1>
<h1>New Release! Now v2! This request was processed by host: 64724167bc8d</h1>
<h1>New Release! Now v2! This request was processed by host: 64724167bc8d</h1>
<h1>New Release! Now v2! This request was processed by host: 64724167bc8d</h1>
<h1>New Release! Now v2! This request was processed by host: 64724167bc8d</h1>
<h1>New Release! Now v2! This request was processed by host: 64724167bc8d</h1>
<h1>New Another Release! Now v3! This request was processed by host: fdf5019381c2</h1>
<h1>New Release! Now v2! This request was processed by host: 64724167bc8d</h1>

なお,今回は手順を簡単にするために Envoy を再起動したけど,Route Discovery Service (RDS) を使えば,自動的に反映できるようになる.xDS 関連は以下の Try Envoy が参考になる.

kakakakakku.hatenablog.com

kakakakakku.hatenablog.com

Step.6 「Rollout 100% Traffic」

最後は割合を 100% にする.100% なら weighted_clusters を使う必要はなさそうだけど,実際に動くことを確認する手順になっていた.

route_config:
  virtual_hosts:
  - name: backend
    domains:
    - "*"
    routes:
    - match:
        prefix: "/service/1"
      route:
        cluster: service1
    - match:
        prefix: "/service/2"
        headers:
        - name: "x-canary-version"
          exact_match: "service2a"
      route:
        cluster: service2a
    - match:
        prefix: "/service/2"
      route:
        cluster: service2
    - match:
        prefix: "/service/3"
      route:
        weighted_clusters:
          clusters:
          - name: service3b
            weight: 100

構成図は以下のようになる.

f:id:kakku22:20200112133003p:plain

まとめ

  • 「Try Envoy」のコンテンツ「Implementing Blue / Green Rollouts」を試した
  • Envoy は「高機能ロードバランサ」の側面として様々なルーティング設定ができることを学んだ

引き続き,進めていくぞ!

プルリクエスト

試しながら気付いた誤りを修正してプルリクエストを送っておいた!

github.com

Try Envoy 関連

Material-UI の GridList コンポーネントを実装する

前回の記事から少し時間がたってしまったけど,Material-UI を使ったプロトタイプ開発を続けている.今回は GridList コンポーネントをサンプルコードを参考に実装しながら理解を深めていく.グリッドリストはフォトリストのようにコンテンツを並べる UI のことを言う.過去には List コンポーネントと Snackbars コンポーネントの記事を書いていて,コンポーネントの調査シリーズも定期的に書いていく.

material-ui.com

なお,実装したサンプルコードは GitHub に公開してある.TypeScript で create-react-app を実行してから実装を進めた.記事に載せるコードはポイントを限定し抜粋するため,実際にコード全体を見る場合は GitHub を参照して頂ければと!

$ create-react-app sandbox-material-ui-grid-list --template typescript
$ cd sandbox-material-ui-grid-list

$ npm install @material-ui/core
$ npm install @material-ui/icons

$ yarn start

github.com

今までは create-react-app --typescript を使っていたけど,最新版の v3.3.0 から以下の警告が出るようになっていた.--typescript オプションは廃止になり,今後は create-react-app --template typescript を使う必要がある.覚えておこう.

The --typescript option has been deprecated and will be removed in a future release.
In future, please use --template typescript.

GridList コンポーネント

GridList コンポーネントはグリッドリストの「全体枠」を定義する.

主要なパラメータは2個ある.まず,cellHeight プロパティを使うと,グリッドリストの「高さ」を設定できる.ピクセル固定もできるし,自動なら auto も設定できる.次に,cols プロパティを使うと,グリッドリストの「タイル数(横)」を設定できる.GridList コンポーネントで使えるプロパティ一覧は以下のドキュメントに載っている.

material-ui.com

サンプルコードの一部を載せておく.

const App: React.FC = () => {
  const classes = useStyles();

  return (
    <div className={classes.root}>
      <GridList cellHeight={200} className={classes.gridList} cols={3}>
      </GridList>
    </div>
  );
}

GridListTile コンポーネント

GridListTile コンポーネントはグリッドリストの「タイル」を定義する.

GridList コンポーネントと GridListTile コンポーネントを組み合わせることにより,「全体枠」の中に「タイル」を配置できる.GridList 側で設定した cols に対して,GridListTile 側でさらに cols を設定できる.cols="1" にすれば「等間隔にタイルを敷き詰める」ことができるし,cols="1"cols="2" を組み合わせれば「特定のタイルのサイズを変える」こともできる.GridListTile コンポーネントで使えるプロパティ一覧は以下のドキュメントに載っている.

material-ui.com

サンプルコードの一部を載せておく.

const App: React.FC = () => {
  const classes = useStyles();

  return (
    <div className={classes.root}>
      <GridList cellHeight={200} className={classes.gridList} cols={3}>
        <GridListTile key="cat" cols="2">
          <img src={cat} alt="cat" />
        </GridListTile>
        <GridListTile key="deer" cols="1">
          <img src={deer} alt="deer" />
        </GridListTile>
        <GridListTile key="kingfisher" cols="1">
          <img src={kingfisher} alt="kingfisher" />
        </GridListTile>
        <GridListTile key="koala" cols="1">
          <img src={koala} alt="koala" />
        </GridListTile>
        <GridListTile key="pelikan" cols="1">
          <img src={pelikan} alt="pelikan" />
        </GridListTile>
        <GridListTile key="rabbit" cols="1">
          <img src={rabbit} alt="rabbit" />
        </GridListTile>
        <GridListTile key="tiger" cols="2">
          <img src={tiger} alt="tiger" />
        </GridListTile>
      </GridList>
    </div>
  );
}

実際に動作確認をすると,cols="2" に設定したネコとトラは2タイルを結合したサイズになっている.なお,動物の素材は Pixabay から取得している.

f:id:kakku22:20200112123227p:plain

GridListTileBar コンポーネント

GridListTileBar コンポーネントはタイルの上に表示する「追加情報」を定義する.

主要なパラメータは3個ある.まず,titlesubtitle を使うと追加情報をタイルの上に表示できる.さらに,actionIcon を使うと「ボタンを押したら○○」というトリガーの実装と連携することもできる.GridListTileBar コンポーネントで使えるプロパティ一覧は以下のドキュメントに載っている.

material-ui.com

サンプルコードの一部を載せておく.titletitle + subtitletitle + subtitle + actionIcon の計3パターンを実装した.

const App: React.FC = () => {
  const classes = useStyles();

  return (
    <div className={classes.root}>
      <GridList cellHeight={200} className={classes.gridList} cols={3}>
        <GridListTile key="cat" cols="2">
          <img src={cat} alt="cat" />
          <GridListTileBar
            title="Cat"
          />
        </GridListTile>

        {/* 中略 */}

        <GridListTile key="koala" cols="1">
          <img src={koala} alt="koala" />
          <GridListTileBar
            title="Koala"
            subtitle="So Cute !"
          />
        </GridListTile>

        {/* 中略 */}

        <GridListTile key="tiger" cols="2">
          <img src={tiger} alt="tiger" />
          <GridListTileBar
            title="Tiger"
            subtitle="So Cool !"
            actionIcon={
              <IconButton className={classes.icon}>
                <InfoIcon />
              </IconButton>
            }
          />
        </GridListTile>
      </GridList>
    </div>
  );
}

実際に動作確認をすると,ネコとコアラとトラに追加情報が表示されている.

f:id:kakku22:20200112123308p:plain

ListSubheader コンポーネント

ListSubheader コンポーネントはグリッドリストの中に「区切り」を定義する.

GridListTile コンポーネントの中に ListSubheader コンポーネントを含めるため,サイズなどは GridListTile コンポーネントの cols プロパティを使う.ListSubheader コンポーネントで使えるプロパティ一覧は以下のドキュメントに載っている.

material-ui.com

サンプルコードの一部を載せておく.写真を撮影した年を区切りとして追加した.

const App: React.FC = () => {
  const classes = useStyles();

  return (
    <div className={classes.root}>
      <GridList cellHeight={200} className={classes.gridList} cols={3}>
        <GridListTile key="Subheader" cols={3} style={{ height: 'auto' }}>
          <ListSubheader component="div">2018</ListSubheader>
        </GridListTile>
        <GridListTile key="cat" cols="2">
          <img src={cat} alt="cat" />
          <GridListTileBar
            title="Cat"
          />
        </GridListTile>
        <GridListTile key="deer" cols="1">
          <img src={deer} alt="deer" />
        </GridListTile>

        {/* 中略 */}

        <GridListTile key="Subheader" cols={3} style={{ height: 'auto' }}>
          <ListSubheader component="div">2019</ListSubheader>
        </GridListTile>
        <GridListTile key="rabbit" cols="1">
          <img src={rabbit} alt="rabbit" />
        </GridListTile>
        <GridListTile key="tiger" cols="2">
          <img src={tiger} alt="tiger" />
          <GridListTileBar
            title="Tiger"
            subtitle="So Cool !"
            actionIcon={
              <IconButton className={classes.icon}>
                <InfoIcon />
              </IconButton>
            }
          />
        </GridListTile>
      </GridList>
    </div>
  );
}

実際に動作確認をすると,2018年の区切り(ヘッダー)と2019年の区切り(ヘッダー)が表示されている.

f:id:kakku22:20200112123336p:plain

まとめ

Material-UIGridList コンポーネントを実装しながら理解を深めた.コード量を少なくグリッドリストの実装ができて便利だった.引き続きコンポーネント調査を続けていくぞ!

Material-UI 関連記事

kakakakakku.hatenablog.com

kakakakakku.hatenablog.com

2019年(7-12月)のプルリクエストを振り返る

OSS に送ったプルリクエストを振り返ろうと思う.プルリクエストの振り返りは2016年からしているけど,2019年は前半に多く送った背景もあり,既に「2019年(1-6月)」の期間で記事を書いている.今回は後半として「2019年(7-12月)」を振り返ろうと思う.後半の累計は「計5件」となり,2019年全体だと「計17件」となる.過去の振り返りは以下にある.

プルリクエストを振り返るための検索

プルリクエストを振り返るために GitHub の検索条件を使う.今回は「2019年(7-12月)」に限定する必要があるため created:2019-07-01..2019-12-31 を使う.

is:pr is:public author:kakakakakku -user:kakakakakku created:2019
is:pr is:public author:kakakakakku -user:kakakakakku created:2019-07-01..2019-12-31

2019/11

awsdocs/aws-cloudformation-user-guide

ドキュメントを読みながら AWS CloudFormation テンプレートの写経をしていたら,プロパティ名に誤りを発見したため,修正した.

github.com

awslabs/aws-sam-cli

AWS SAM を検証していたら,CLI のエラーメッセージに誤ったオプションが記載されていたため,修正した.

github.com

2019/12

envoyproxy/katacoda-scenarios

11月から Envoy を学ぶため「Try Envoy」のコンテンツを活用している.Envoy のドキュメントにデッドリンクがあったり,名称が統一されていなかったり,進めていると気になる誤りがあったため,コツコツと修正している.Merge はされているものの,実際に Katacoda にデプロイされるタイミングはわからず,気長に待ちたいと思う.

github.com github.com github.com

まとめ

2019年(7-12月)は「計5件」のプルリクエストを送ることができた.日に日にコードを書く機会が減っていることもあり,プルリクエストを送る機会も減っているけど,来年もコツコツと頑張る!