モダンなWebフロントエンドの技術とAMP

モダンなWebフロントエンドのフワームワークやツールとAMPについて紹介します。

モダンなWebフロントエンドの技術とAMP

リクルートテクノロジーズ兼リクルートライフスタイルのASGチームに所属しているフロントエンドエンジニアの可児です。本記事は、リクルートライフスタイルアドベントカレンダー4日目の記事です。 本記事では、リクルートライフスタイルで取り組んでいる新規Webサービスのモダンなフロントエンド開発に関することとして、Next.jsやAMPについて紹介します。

目次

  1. はじめに
  2. モダンなWebフレームワーク
    • React/Next.js
    • TypeScript
    • styled-components
  3. AMP
    • AMPとは
    • AMPの開発パターン
    • Next.jsとAMP
    • AMPキャッシュ
    • AMP と 非AMP の共存
    • 検索結果カルーセルとSEO
  4. AMPの開発における注意点
  5. まとめ

はじめに

リクルートライフスタイルでは、じゃらんやホットペッパーグルメ、ホットペッパービューティーといった従来のWebサービスだけではなく、様々な新しい領域の開拓を狙ったサービスにもチャレンジしています。組織としては柔軟に技術選定することが可能な新規Webサービス開発を通して、最新の技術スタックを取り入れた開発を行い、有用性を確認した上でリクルートの様々なサービスに横展開していくことで、リクルート全体のWebサービス開発のDX(Developer eXperience)とUX(User eXperience)を高めていきたいと考えています。

ホテルや飲食店といったクライアント様の情報を、Webを介して様々な情報の中からより素早く適切にユーザにお届けするための1つの施策として、Webサービスを高速に表示することが求められています。それを実現するための技術として、最近ではGoogleが提唱するAMPという技術に注目が集まってきています。今回は、実際にリクルートライフスタイルの開発現場で利用しているモダンなWebフレームワークとしてNext.js、周辺技術としてTypeScript、styled-components、そして上述のAMP、それらの技術スタックでAMP対応のページを開発する方法と注意点、AMPのメリット・デメリットなどについて紹介します。

紹介技術ロゴ

モダンなWebフレームワーク

React / Next.js

Reactは近年のWebサービス開発において広く使われているUIフレームワークです。また先日の Chrome Dev Summit 2019 のキーノートやWebフレームワークの技術を紹介するセッションでは、Reactで容易に開発可能なWebフレームワークである Next.js が大々的に紹介されました。UIフレームワークとしてのReact、それを利用するWebフレームワークとしての Next.js が Webサービス開発の代表格となりつつあります。 Next.js はフロントエンド開発で一種の鬼門であるwebpackの設定であったり、BFFのWebサーバの構築やサーバサイドレンダリングを、zero config 、つまり何の設定もなくいきなり Reactで書きはじめることができます。周辺プラグインも充実し、公式のGitHub内には多数の example も用意され、後述する AMP のサポートももちろん行われています。リクルートでも Next.js を活用したWebサービス開発が多数進められています。

TypeScript

JavaScript には型がないため、これまでも様々なAltJSが世の中に出回ってきましたが、いまはTypeScriptが非常に強い印象を受けます。TypeScript は @DefinitelyTyped の充実さが光っており、有名なモジュールにはほとんど型定義が用意されてきています。今後のモジュール開発も TypeScriptが利用されるものも増え、より一層型で縛ることのできる世界に近づいていくものと思われます。上述の Next.js ではデフォルトでTypeScriptの開発が可能です。

styled-components

CSS in JS の代表格の1つとして、styled-components というライブラリがあります。近年では emotion なども人気が出てきており、いくつかの選択肢があるように思います。styled-components でも emotion でも js で変数値を style に利用することができます。

1
2
3
4
5
6
7
8
9
10
11
const Color = {
  Border: {
    Default: "#e4e4e4",
    Fixed: "#b8b8b8"
  }
  ...
}

const StyledItem = styled.div`
  border-top: 1px solid ${Color.Border.Default};
`;

Next.js では styled-components を活用した example も紹介されています。

AMP

AMP とは

最近のWebサービスはよりリッチなUI/UXを提供するようになってきています。それに伴って JavaScript, CSS が肥大化したり、表示する画像は高画質化したりしていて、結果的に表示したいWebページのサイズが増加しています。さらにWebサービスに対して改善を加え続けていくと、Webページ内に不要なコードが残ってしまったりすることでページのサイズが大きくなってしまい、ページのレンダリング速度が遅くなることで顕著にUXが悪くなることがあります。 それらの問題に対し、Google はパフォーマンスを低下させないための仕組みとして AMPを提唱しています。AMP は “Valid な状態” が明確に定義されています。例えば、

  • AMP ページには任意のJavaScriptは含めないこと
  • CSS は 50KB以内にすることなど

ルールを制約として設けることで AMP Valid な状態にしておくことでページサイズを抑えレンダリングの速度を遅くしないようにしています。 AMPは独自のAMP用の Validator を用意することで、AMP Valid な状態かどうかを確認することができます。AMP Valid な状態でWebページを公開すると、Google 側が検索結果に AMP Valid であることを示す稲妻マークを表示してくれるため、ユーザはそのページがAMPであり高速に表示されることがわかります。そして、Googleは自動的にAMP ValidなページをGoogleのCDNにキャッシュとしてのせてくれるため、より高速にユーザに検索結果を表示することができます。

AMP では任意のJavaScriptが記述することが許容されない代わりに、AMP用の UI コンポーネントが提供されています。Web Components として作られている AMP コンポーネントは、 <amp-xxx> といった形式のタグとして html に書くことで簡単に利用できます。 例えば、画像を表示する <amp-img> は従来の <img> タグと似たタグとなっています。しかし、 <img> が属性値で指定された src の画像を表示するだけのものであるのに対し、 <amp-img> はそれ単体で、レスポンシブに表示することを可能にするとともに、自動的に lazy load 機能が働き、画像がブラウザに表示され必要となったタイミングでダウンロードされるようになります。このように AMP コンポーネントは、単体でパフォーマンスに考慮された設計がなされているHTMLタグとして活用することが可能です。 そのほかにも、 <amp-sidebar><amp-carousel> といった、サイドバー、画像のカルーセル表示など、自前で開発しようとすると大変そうなコンポーネントもすでに用意されているので、十分に活用することができます。最近では amp-story と呼ばれる新たに大きな機能がリリースされ注目されています。

AMPの開発パターン

AMP の開発パターンには2種類あります。

  • Hybrid AMP
  • Full AMP(AMP First とも呼ばれる)

Hybrid AMP はオリジナルの AMP Valid ではない Webページに対して、 AMP用の AMP Valid なページをカノニカルとして用意するものです。実際には、既存のオリジナルWebサイトや記事がすでにリリースされている場合に、Google検索による流入増加を目的としてAMPページを用意する形で開発が進められることが多いため、 Hybrid AMP の開発パターンの方が現在は多いです。

しかし、Hybrid AMP でAMPのページを開発することだけが目的となってしまい、本来のオリジナルのページとはUXが異なる簡素なページを開発されるケースが見られます。AMPを開発しているGoogleは、基本的にはAMPとオリジナルのページの UX は大きく変えないことを推奨していますし、ユーザ体験としても同じページを見ているのに、AMPページを見る場合とオリジナルのページを見る場合で、機能やUIが異なってしまうのは体験上良いものとは言えないため、オリジナルのページとほぼ同等のAMPページを作り込むべきです。

新規でページを開発する場合には Hybrid AMP では、同じWebページをオリジナル、AMPの2ページ分開発してしまうことになり、二重開発が発生してしまいます。そのため、Full AMP で開発することで、はじめからAMPを利用して開発を行うことで、二重開発を避けられます。

ちなみに、AMPコンポーネント は必ずしも AMP Valid な状態で使う必要はありません。AMPコンポーネントは単なる Web Components として利用することもできます。AMPコンポーネントそのものとして有用なものも多いので、Webページの開発を行う際に部分的にAMPコンポーネントを一種のUIライブラリとして利用することで、パフォーマンスを担保しつつ、開発効率も高めることができます。

Next.js と AMP

Next.js ではpagesフォルダ配下のファイルが自動的にファイル名でルーティングされ、1つのページとして機能し表示されます。デフォルトの設定でサーバサイドレンダリング(SSR)されます。

AMP 化は容易で、pages のファイル内で export const config = { amp: true }; と書いておけば、AMP を有効化するために必要なスクリプト等を含んだ形でSSRを行ってくれます。ただし、それだけで自動的にAMP Valid になるわけではないので注意が必要です。

AMP Valid かどうかは Next.js がSSRするタイミングで、AMP用のValidationを通してくれるので、Next.jsの標準出力で確認することができます。AMP Validにするためには、ページやコンポーネント内にクライアントサイドで実行されるJavaScriptを書かず、 CSSも50KB以内に抑えつつ、<head> 内の1箇所にまとめてに書く必要があります。Chrome Extensionや、 AMP ValidatorがWebページになっているので、それらも活用できます。

AMPキャッシュ

AMP Validな状態だと、AMPページのキャッシュ(AMP キャッシュと呼ぶ)がGoogleのCDNにのります。GoogleのAMPキャッシュにのることで、Googleの検索結果でカルーセル的に表示されて検索結果表示に優遇されるようなことがあったり、AMPキャッシュにのっているページは検索結果ページが表示されている状態であらかじめ(ユーザがクリックする前に)HTMLドキュメントをダウンロードしておき、ユーザが実際にクリックしたら高速に表示することができるようにしたりします。

しかし、AMPキャッシュが返されるということは最新のHTMLドキュメントがSSRされるわけではなく、前回キャッシュにのったタイミングのものがAMPキャッシュからユーザに届けられることになります。そのため例えば、飲食店の予約情報などといった変化の激しいデータがAMPキャッシュにのってしまうと、ユーザに正しくないデータが届けられてしまう可能性があることに注意が必要です。ただAMPキャッシュは Stale-While-Revalidate モデルに従ったものになっています。つまりユーザの誰かがキャッシュにアクセスしたタイミングで、GoogleがオリジナルのサーバにアクセスしAMPキャッシュを更新させることが可能になりますので、問題になるケースは絞られるのではないかと思います。

また、AMPキャッシュはGoogleのCDNにのっているためGoogleのドメインとして表示されてしまうことにも注意が必要です。基本的にページの表示そのものに問題はありませんが、ユーザがURLバーを見てどこのサイトのものなのかわかりづらかったり、モニタリング分析系の通信で思ったようなデータを収集できないケースがあります。AMP用の分析タグとして amp-analytics が用意されているものの、例えばITP2.3の影響で Safari では別ドメインによるCookieの書き込みやLink Decorationであると判断されてしまうことで、これまで取得できていたような分析データが収集できないかもしれないので注意が必要です。

ちなみにChromeブラウザのみを対象にすれば、Signed HTTP Exchange (SXG) という仕組みを適用することができます。これはWebページへのリクエストとレスポンスに対して署名を行いAMPキャッシュとしてGoogle側が保管しておき、Chromeブラウザがその署名が正しいものであると検証できた場合に、Googleから配信された署名つきAMPキャッシュを本来のオリジナルのドメインとして扱うことができるものです。そのため、Googleから配信された AMPキャッシュをブラウザで表示しているにも関わらず、 URLバーの表示はオリジナルのURLが正しく表記されるようになります。CDNサービスを提供しているCloudflareは簡単にSXG化させることができます。しかしながらSXGの仕組みは Chromeブラウザでしか実装されていないため、現状Safariでは変わらずGoogleドメインとして扱われてしまいます。

AMP と 非AMP の共存

Full AMPで開発を進めていたときにユーザ固有のログインページなど、AMP Valid である必要がないページも同じサービス内に作る場合でも、Next.jsで開発していればpagesで定義するページに対し、 amp: true の config を用意しなければそのままReactのページとしてレンダリングされることになります。つまり、開発体系を大きく変えることなくコンポーネントも使い回しながら開発を進めることができるため、AMP ValidとAMP Validではないページを共存させることは難しくありません。

検索結果カルーセルとSEO

Googleの検索結果でカルーセル表示になるページは、ニュース記事や飲食店情報といった限定された分類のページに限られています。商品情報や店舗情報といったその他の内容のものはAMP Validなものにしても検索結果として優遇されるカルーセルになるとは限らないことに注意が必要です。

また、SEOとしてAMPページが優遇され検索結果が上位になるといったことがGoogleから明言されているわけではありません。しかし、Googleはページの表示パフォーマンスはSEOに影響します。AMP Validにすれば必ず検索結果が上位になるわけではありませんが、ページのレンダリング速度は一定の高速化が可能になり、これは間接的にSEOへの効果が寄与されるものと言えます。

AMPの開発における注意点

AMP では任意のJavaScriptを記述して動的な処理をページ内に含められない代わりに、AMPコンポーネントに対して動的な処理を記述することが可能です。AMPコンポーネントに対しても制約上JavaScriptを記述できないので、HTML属性にスクリプトライクな文字列を記述して、動的な処理を定義します。例えば <amp-sidebar> でサイドバーを利用する際は、サイドバーの開閉処理をボタンなどに対して on 属性で定義することができます。

1
2
3
4
5
6
7
8
9
  // サイドバー本体
  <amp-sidebar id="sidebar">
    <div>
      サイドバーの中身
    </div>
  </amp-sidebar>

  // idがsidebarのサイドバーを開くトグルボタン
  <button on="tap:sidebar.toggle">開く/閉じる</button>

この時、開発時にNext.jsでTypeScriptを利用している場合、AMP独自のWeb ComponentsはReactのJSXとして型が用意されているわけではありません。

型違反

現時点ではAMP公式の型定義が公開されているわけではありませんので、開発者がAMPコンポーネント向けに型定義をそれぞれ用意する必要があります。また、on 属性自体ももともとbuttonタグには存在しないものなので、型違反になるためこちらも同様にHTMLAttributesの型定義の拡張が必要です。

amp-sidebarの型の例

また styled-components と組み合わせる場合には、 const StyledSidebar = styled["amp-sidebar"] のようにAMPコンポーネントの style を直接修飾することはできず、 <amp-sidebar> をラップしたReactコンポーネントを定義し、styled関数で囲うことでスタイルを修飾する必要があります。

このようにAMPが既存のHTMLにないタグ名だったり属性値を使用しているために、TypeScriptやstyled-componentsといった他のライブラリで一般的な仕様上のHTMLを想定されたものになっているときに不具合が生じることがあるので注意が必要です。

一方で、styled-componentsではもともとAMP用の on 属性が付与されたHTMLコンポーネントにスタイルを修飾すると on 属性の情報が消えてしまうバグがありましたが、今は解消されています。このようにだんだんとAMPとモダンなライブラリとの親和性が高くなってきていることも事実です。

AMPそのものが発展途上であるがゆえに、AMPそのものにもバグが入り込んでしまうことがあります。バグが入り込んでしまうこと自体はライブラリとして利用している以上逃れることができません。しかし、npm などで配信されるモジュールに対しては、package.jsonでモジュールのバージョンを指定しておき、必要に応じてバージョンを上げたりビルドし直すことで異常を確認できますが、 AMPではAMPコンポーネント向けのスクリプトがCDN経由で配信されているため、パッチがあたった瞬間にCDN側が更新されることに伴い、リリースされているプロダクションで参照しているスクリプトが急に新しくなることがあります。ここにバグや想定外の仕様変更が入り込んでいる場合、いきなりプロダクションのサービスに直に影響が出ることがあり得ます。つまり、AMPコンポーネントやAMP用のスクリプトはある一定の依存度を保ったり、エラーハンドリングをきめ細やかにしておくなどの細心の注意が必要になります。

また、DX的にはAMPは上述の通り、スクリプトライクな文字列でロジックを管理しなければなりません。これはAMP独自のスクリプトであるため、はじめてAMPを触る場合には学習コストがかかります。それに加えて、今のところこのAMP 独自のスクリプトに対して適切なシンタックスハイライトが行われるエディタであったり、lint機能は提供されていません。せっかくTypeScriptを利用していても、このままでは型を効かせることもできません。そのため、もしきちんとAMP独自のスクリプトを管理するためには、AMP用のスクリプトビルダーを内部で開発するなどして、適切な管理が必要になります。

まとめ

本記事ではWebフレームワークとしてのNext.jsやGoogleの提唱しているAMPについて紹介しました。

これまでの内容を踏まえ、私が考えるAMPのメリットは、以下になると思います。 - Validな状態にするための制約に従うことで、パフォーマンス低下を防ぐことができる点 - AMPキャッシュにのせることによる検索結果のカルーセルと表示高速化 - AMPコンポーネントそのものの有用性

一方でAMPによるデメリットは以下だと思っています。 - AMP Validにする厳しい制約による機能開発の難しさ - AMPを扱うためのスクリプト更新への追従 - AMPキャッシュやAMPの制約下で分析、広告タグが利用しづらいこと

もちろんメリット・デメリットは上記に挙げた点だけではありません。AMPを導入することによる学習コストの増加や制約による開発が難しくなることはあります。しかしながら、AMPの根本的な考え方である、必要最低限のスクリプトやCSSでWebページの高度なパフォーマンスを担保しながらユーザ体験が良いものを提供していくことはどのような開発を行うにも参考にすべきことであると思います。例えば、AMPコンポーネントをWeb Componentsとして利用しながら、パフォーマンスバジェットをlighthouse CIで管理し、パフォーマンス低下を防ぎながらサービス開発を行ったとしても一定の同様の効果を得られると思っています。すべての技術に言えることですが、開発するサービスや開発チームにとってどのような技術を組み合わせることがベストなのかどうか判断しながら先進的なフレームワークを取り入れて開発を行なっていくべきかなと私は思っています。

最後になりますが、 リクルートライフスタイルの開発チームリクルートテクノロジーズの開発チームではフロントエンドエンジニア・モバイルアプリエンジニア・サーバサイドエンジニア・インフラエンジニア・機械学習エンジニア等々幅広く募集しています!!!

可児 潤也

(フロントエンドエンジニア)

リクルートテクノロジーズ兼リクルートライフスタイルでフロントエンドをかじってます。

Tags

Jenkins XによるPreview環境構築

Jenkins XによるPreview環境構築

本記事は リクルートライフスタイル Advent Calendar 2019 3日目の記事です。

じゃらんnetを担当している永井です。

最近、案件ごとに独立して動作確認できる環境を作りたくて、Jenkins Xを検証していました。 Jenkins Xはまだ情報が少なく、一筋縄では行かなかったので本記事ではその構築過程をご紹介します。

Jenkins X

Jenkins Xは、Git/Docker/Kubernetesの利用を前提として構築・運用を可能な限り自動化してくれるCI/CDソリューションです。 jx create clusterと叩けばGKEEKSなどに標準的なKubernetesクラスタを作成してくれ、 jx installと叩けば対象のKubernetesクラスタにJenkins XをインストールしてGitHubにwebhookまで作成してくれます。 Webコンソール画面は基本必要なくなり、jxコマンド経由で各ジョブの状況も確認できます。

Jenkins Xでできることは全てJenkinsと各種プラグインを活用することで実現可能らしいのですが、 JenkinsやKubernetesまわりについて深く知らずとも幾つかのコマンドを実行していくことで適したCI/CD環境を構築できることが魅力です。

私も、普段はFlutterを推進したり、 Spring BootをGAECloud Runで動かしたりといった具合で、 素のJenkinsをKubernetesに最適化しろと言われると、正直知識が不足していて全然イメージが湧きません。

しかしJenkins Xであれば、これからご紹介していくように各技術への理解が曖昧でも(幾つかのissuesと向き合いながらではありますが)モダンなCI/CDを構築・運用できそうです。

目的

本記事では、特にJenkins Xのpreview環境に注目していきます。

異なる開発者たちが、複数の機能追加・改修を担当しており、それぞれを独立して動作確認したい、という状況はよくあることだと思います。 これまでは、動作確認したい案件ごとに都度環境構築するなどしていましたが、手間も費用も掛かって非効率です。 Kubernetesを活用すれば、リソースを効率的に使いながら、それぞれの環境を独立して動作させることができます。

Jenkins Xはその構築と運用の手助けをしてくれるということで、今回検証してみることにしました。

構築

構築にあたり、以下を前提に置いています。

  • GitHub Enterpriseとの連携(GitHubとGitHub EnterpriseではJenkins Xの設定も一部異なります)
  • GitHub Enterpriseとの通信は固定IPでなければならない

Jenkins Xは様々なKubernetes環境に対応していますが、 今回は最も対応が進んでいそうなGKEと、実際構築を予定しているEKSの2つを試しました。

Kubernetesクラスタ作成

GKEの場合

GKEで「GitHub Enterpriseとの通信は固定IPでなければならない」をクリアするためには、VPCとNATゲートウェイを用意した上で、jx create cluster gkeではなく自前でクラスタを作成する必要があります。 jx create cluster gkeを実行すると、限定公開クラスタ(private cluster)が無効な状態でクラスタが作成されるため、 NATゲートウェイのIPアドレスでGitHub Enterpriseと通信してくれません。

EKSの場合

EKSの場合は、jx create cluster eksを実行すると、実質eksctl create clusterが実行され、 public subnets3つとprivate subnets3つ、そしてIAMロールとInternet/NATゲートウェイが作成されます。 GitHub Enterpriseとの通信には、ここで作成されたNATゲートウェイのIPアドレスを使います。

このとき、jx create cluster eksではなくeksctl create cluster --managedを実行すると、最近使えるようになったEKSのManaged Node Groupsを利用できます。 ここで作成されたManaged Node Groupはpublic subnetsに作成されており、その通信はNATゲートウェイを通りません。 今回は、こうして作成されたManaged Node Groupを一度削除して、 改めてprivate subnetsを選択した新しいManaged Node Groupを作成することでNATゲートウェイを通るようにしました。 ここで、Nodes用のロールは自動作成されたIAMロール(eksctl-<cluster-name>-nodegro-NodeInstanceRole-<id>)を選択します。

jx create cluster eksを実行する場合は、そのままだとこの後説明する2通りのJenkins Xインストールのうちdeprecatedな方が実行されるので、 ここでは--skip-installationオプションを付けて実行することをオススメします。

Jenkins Xインストール

Jenkins Xのインストール方法には現在2通り存在します。

コマンド 説明
jx install 従来の方法。コマンドに各オプションを付与したり、標準入力経由で設定値を入力していく。2020/01/02にdeprecatedになる予定。
jx boot Jenkins Xの設定もgitで管理する方法。今後はなるべくこちらを利用することが推奨されている。

これを見ると「jx bootを使おう」となると思うのですが、jx installだと問題ないけれどjx bootでは躓くissuesも幾つかあるようです。 一方で、jx installで発見されたissuesは、jx bootに切り替えることを提案されて終わっていたりもします。 jx bootを試しながら、問題があればissuesやpull requestsを作成して地道に進んでいくことが建設的なのかもしれませんが、 差し当たりどちらを使っていくか悩ましいところです。

jx install

1
2
3
4
5
6
7
$ jx install --provider={gke|eks} \
  --git-provider-url=https://<github enterprise domain> \
  --no-default-environments \
  --domain=<jenkins x domain> \
  --exposecontroller-urltemplate='"{{.Service}}-{{.Namespace}}.{{.Domain}}"' \
  --urltemplate='"{{.Service}}-{{.Namespace}}.{{.Domain}}"' \
  --verbose

のように実行します。 今回欲しいのはpreview環境のみなので、--no-default-environmentsオプションを付与することでデフォルトで作成されるstaging/production環境を作成しないようにします。 --exposecontroller-urltemplate--urltemplateは、SSL証明書を*.<domain>で作成できるように指定しています(デフォルトは'"{{.Service}}.{{.Namespace}}.{{.Domain}}"')。

コマンドを実行すると、以下のような選択を求められます。

1
2
3
? Select Jenkins installation type:    [Use arrows to move, space to select, type to filter]
> Serverless Jenkins X Pipelines with Tekton
  Static Jenkins Server and Jenkinsfiles

残念ながら、前者はGitHub以外に対応していないようです。 そのため、GitHub EnterpriseやBitBucketを利用している場合は後者を選択しましょう。

しばらくするとjxing-nginx-ingress-controllerというロードバランサーが立ち上がるので、

1
2
3
$ kubectl get services -n kube-system
NAME                                  TYPE           CLUSTER-IP       EXTERNAL-IP                                                                    PORT(S)                      AGE
jxing-nginx-ingress-controller        LoadBalancer   XXX.XXX.XXX.XXX   xxxxx.ap-northeast-1.elb.amazonaws.com   80:xxxxx/TCP,443:xxxxx/TCP   9m20s

上記EXTERNAL IPを*.<domain>の向き先として設定する必要があります。

このあとは、コンソールに表示される指示に従っていけば、無事Jenkins adminユーザーのパスワードが表示され、http://jenkins-jx.<domain> でアクセスできるようになります。

HTTPSでアクセスしたい、という場合は工夫が必要です。 基本的には jx update ingress --namespaces=jx --verbose と実行すれば良いのですが、GKE/AWSともにそのまま放っておくと成功しません。 こちらにあるように、 part0-configmap.yamlを編集してkubectl applyする必要があります。

jx boot

jx installは工夫が必要ながらも何とかJenkins Xをインストールできました。jx bootはどうでしょうか。

まず、現時点でHelmはv2.15.0未満である必要があります

その上で、Jenkins Xの設定値を管理するレポジトリをenvironment-<kubernetes-cluster-name>-devの名前で用意します。 中身は、 jenkins-x/jenkins-x-boot-config の内容でpushします。

この各yamlファイルをローカルで修正し、jx bootすることでJenkins Xのインストール・更新ができます。

今回はpreview環境のみが必要なので、staging/production環境のための設定は削除します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
--- a/env/jxboot-resources/values.tmpl.yaml
+++ b/env/jxboot-resources/values.tmpl.yaml
@@ -65,17 +65,6 @@ gitops:
     dockerRegistryOrg: ""
 {{- end }}

-
-  staging:
-    repo: "{{ .Environments.staging.repository }}"
-    owner: "{{ .Environments.staging.owner | default .Requirements.cluster.environmentGitOwner }}"
-    server: ""
-
-  production:
-    repo: "{{ .Environments.production.repository }}"
-    owner: "{{ .Environments.production.owner | default .Requirements.cluster.environmentGitOwner }}"
-    server: ""
-
 storage:
   logs:
     url: "{{ .Requirements.storage.logs.url }}"

jx-requirements.ymlの各設定値はこちらを参照して設定していきましょう。 GitHub Enterpriseの場合、webhookはlighthouseにする必要があります。

また、secretStorageは現時点localでなければならないようです。 GKE/AWSともに、 secretStoragevaultにすると失敗してしまいます。

修正が終わったら、environment-<kubernetes-cluster-name>-devの直下で jx boot --verbose を実行します。

1
2
3
4
DEBUG: Applying Helm hook post-upgrade YAML via kubectl in file: /tmp/helm-template-workdir-719161591/jenkins-x/helmHooks/env/charts/jenkins-x-platform/charts/expose/templates/job.yaml
DEBUG: job.batch/expose created

DEBUG: Waiting for helm post-upgrade hook Job expose to complete before removing it

と表示されてからしばらくDEBUGログも出ない状態になりますが、気長に待てば無事インストール完了まで行けるはずです。

プロジェクト追加

新しくJenkins Xにジョブを追加したい場合は、jx create quickstartjx create springで始めることをオススメします。 既存のプロジェクトをjx importすることも可能ですが、Jenkinsfileの他に、こちらにあるようなファイル群をプロジェクト内に作成し、正しく記述する必要があります。

jx create quickstartなどでプロジェクトを作成すれば、あとはアプリケーションのソースコードを移植してDockerfileを修正することで基本的には動くようになるはずです。

ただし、EKSの場合はまたもう一工夫必要です。 jx create quickstartなどでプロジェクトを作成すると、自動的にmasterブランチのジョブが走り始めます。 すると以下のようなエラーでジョブが失敗します。

1
2
3
[ERROR] Error parsing the serverURL: https://index.docker.io/v1/,
error: docker-credential-ecr-login can only be used with Amazon Elastic Container Registry.
credentials not found in native keychain

このエラーは、こちらにあるような方法でsecretを修正すれば解消します。

jx bootでJenkins Xをインストールした場合は、environment-<kubernetes-cluster-name>-devにもpull requestが作成されているはずです。 このpull requestをマージして、再度jx bootを実行してから次のステップへ進みましょう。

Preview環境

さて、ここまででmasterブランチのジョブは通るようになり、いよいよpull requestsに対してpreview環境を立ち上げます。 jx create quickstartなどで作成したプロジェクトのJenkinsfileには、既にjx previewコマンドが記述されているはずです。 この箇所を、以下のように修正しましょう。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -17,6 +17,7 @@ pipeline {
         PREVIEW_VERSION = "0.0.0-SNAPSHOT-$BRANCH_NAME-$BUILD_NUMBER"
         PREVIEW_NAMESPACE = "$APP_NAME-$BRANCH_NAME".toLowerCase()
         HELM_RELEASE = "$PREVIEW_NAMESPACE".toLowerCase()
       }
       steps {
         container('nodejs') {
@@ -27,7 +28,9 @@ pipeline {
           sh "jx step post build --image $DOCKER_REGISTRY/$ORG/$APP_NAME:$PREVIEW_VERSION"
           dir('./charts/preview') {
             sh "make preview"
-            sh "jx preview --app $APP_NAME --dir ../.."
+            sh "jx preview --app $APP_NAME --dir ../.. --urltemplate='\"{{.Service}}-{{.Namespace}}.{{.Domain}}\"'"
           }
         }
       }

--urltemplateを追加しているのは、jx installの時と同じ理由です。

また、preview環境に対してHTTPSで通信できるように、以下を修正します。

1
2
3
4
5
6
7
8
9
10
11
--- a/charts/preview/values.yaml
+++ b/charts/preview/values.yaml
@@ -6,7 +6,7 @@ expose:
   config:
     exposer: Ingress
     http: true
-    tlsacme: false
+    tlsacme: true

 cleanup:
   Args:

こうしてpull requestを作成すると、webhook経由でジョブが走り始めます。

例えば、 jx create quickstartnode-http を選択したとします。 Preview用のブランチで、以下のように修正してみます。

1
2
3
4
5
6
7
8
9
10
11
--- a/index.html
+++ b/index.html
@@ -12,7 +12,7 @@
 <body>
        <div class="cover">
                <div class="feature">
-                       <h1>Hello Node Preview</h1>
+                       <h1>Hello Node</h1>
                        <div class="brand">
                                Jenkins <strong>X</strong>
                        </div>

このブランチのpull requestを作成して、remoteにpushしてみます。 すると、 node-xxx という名前のジョブ実行用podが立ち上がり、

1
2
3
4
5
6
7
8
9
$ kubectl get pods
NAME                                        READY   STATUS      RESTARTS   AGE
exposecontroller-59tm2                      0/1     Completed   0          57m
jenkins-845998c594-8zbg5                    1/1     Running     0          61m
jenkins-x-chartmuseum-d87cbb789-dzl4h       1/1     Running     0          61m
jenkins-x-controllerrole-8499688fb5-2f84d   1/1     Running     0          61m
jenkins-x-heapster-ff6df6848-mmb95          2/2     Running     0          61m
jenkins-x-nexus-6bc788447f-6xxgn            1/1     Running     0          61m
nodejs-b1rll                                2/2     Running     0          2m7s

完了次第、 https://<repo-name>-jx-<org-name>-<rep-name>-pr-<pr-number>.<domain>/ というようなURLが生成され、 pull requestに対してURL付きでコメントがpushされます。

pr-comment pr-preview

無事preview環境が出来上がりました! 🎉

クローズしたpull requestsに対するpreviewsは、定期的に削除してくれるようです。

1
2
3
4
5
$ kubectl get cronjobs
NAME                     SCHEDULE         SUSPEND   ACTIVE   LAST SCHEDULE   AGE
jenkins-x-gcactivities   0/30 */3 * * *   False     0        <none>          107m
jenkins-x-gcpods         0/30 */3 * * *   False     0        <none>          107m
jenkins-x-gcpreviews     0 */3 * * *      False     0        <none>          107m

まとめ

いかがでしたでしょうか。

正直まだまだ躓き所が多い印象ではありますが、調べれば何とか解決していけますし、学習・コミット機会と捉えて楽しむこともできそうです。

これを機に、一緒にissuesと向き合う仲間が増えてくれると嬉しいです。

永井 佑樹

(じゃらんnet開発チーム)

じゃらんnetとAirレジを担当しています。

Tags

NEXT