TECH PLAY

株式会社ラクス

株式会社ラクス の技術ブログ

927

はじめに こんにちは!新卒1年目の hachimd です! 先日、先輩エンジニアの方に「 Java でソートする時って Collections 使うんですよね?」って話をしたら「いやいや、 Java のソートは Stream が便利だよ!」って教えていただきました。 そこで今回は、Stream を使って、どうやってソートするのか、どう便利なのかを、Collections を使ったソートと比較してゼロから解説してみようと思います。 考え方から言及しているので、ソートの方法が全くわからない人でも大丈夫です。 なお、今回は JDK11 を使用しています。 目次 はじめに 目次 基本的なソートの考え方 Collections を使ったソート 要素の大小関係が明らかなとき 大小比較の方法を制御したい時 Collections.sort のデメリット Stream を使ったソート Stream を使った単純なソート Stream を使った『人オブジェクト』のソート 3 種類の整数を返す処理でソート comparing によるキーの指定だけでソート 複数のキーでソート 最後に 参考書籍   基本的なソートの考え方 ソートは一言で言うと、「昇順 or 降順で並び替えること」と言えます。 ここで、「名前」と「年齢」を持つ『人オブジェクト』を並び替える際に、「まず名前順で並び替え、名前が同じ時は年齢順で並び替える」というルールにすると、単に昇順・降順では並べられないと感じてしまいますが、『人オブジェクト』の大小関係を決める際に「名前を最優先、次点で年齢」と考えると、あくまで『人オブジェクト』の大小関係に従って昇順・降順に並べているのでシンプルになります。 つまり、ソートしたい要素に対して、どのように大小を決定するかを決めてやれば、あとは API を使ってソートができるということです。 【重要】ソートするのに必要なことは、要素の大小関係を決めてあげること Collections を使ったソート ここではまず、大小関係が明らかなものをソートする方法と、大小関係が明らかでない『人オブジェクト』をソートする方法を解説します。 どちらも Stream が使えるようになる以前によく使われていた、 Collections.sort() を使って解説をして、 Collections.sort() のデメリットにも言及します。その後、 Stream を使ったシンプルでわかりやすいソートの方法を解説していきます。 要素の大小関係が明らかなとき 数値や文字列のように大小関係が明らかなときは、大小関係を決めてやらなくてもソートすることができます。また、ソートの結果は自然順序(明らかな大小関係に基づく昇順)になります。 ソートするには Collections.sort() を呼び出すだけです。 List<Integer> numbers = Arrays.asList( 5 , 4 , 8 , 3 , 1 ); // ソートを実行 Collections.sort(numbers); // 結果を出力 for ( int num: numbers){ System.out.print(num + " " ); // 1 3 4 5 8 } 大小比較の方法を制御したい時 次に、age と name をプロパティにもつ Person をソートすることにします。 Person オブジェクトの年齢差を返す ageDifference メソッドも定義しています。 public class Person { private final int age; private final String name; public Person(String name, int age) { this .name = name; this .age = age; } public int getAge() { return age; } public String getName() { return name; } @Override public String toString() { return "Person{" + "age=" + age + ", name='" + name + ' \' ' + '}' ; } public int ageDifference( final Person other) { return this .age - other.age; } } Person の大小関係がどう決まるのかは我々が定義してあげる必要があります。 Java では、要素の大小比較の方法を自分で決定するには Comparator というインタフェースを利用します。 Comparator は関数型インタフェースで、抽象メソッドとして compare メソッドが定義されています。 cpmpare メソッドの実際の処理に「大小比較の方法」を記述していきます。また、この処理はある決まりに従って書く必要があります。具体的には、「2 つの引数をとり、 第 1 引数が第 2 引数より小さいとする場合は負の整数、両方が等しい場合は 0、第 1 引数が第 2 引数より大きいとする場合は正の整数を返す」ような処理になります。 (参考: Comparator インタフェースの compare メソッド ) それでは「まず年齢順で並び替え、年齢が同じ時は名前順で並び替える」というルールで、実際にソートをする処理を見ていきましょう(ここでは Collectons を使ったソートはめんどくさいなと感じてもらえれば大丈夫です)。 まずはコードを見てみましょう。 List<Person> people = Arrays.asList( new Person( "John" , 20 ), new Person( "Sara" , 21 ), new Person( "Jane" , 21 ), new Person( "Greg" , 35 ) ); // compareメソッドをオーバーライドしてPersonオブジェクトの大小比較の方法を定義する // 比較方法:年齢で比較して同じなら名前で比較 Comparator<Person> personComparator = new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { int ageDiff = p1.ageDifference(p2); if (ageDiff != 0 ) { return ageDiff; } else { int nameDiff = p1.getName().compareTo(p2.getName()); return nameDiff; } } }; // 年齢でソートする // 第1引数:ソート対象のpeople // 第2引数:Personの大小比較方法が定義されたComparator Collections.sort(people, personComparator); // 並びを確認 for (Person person : people) { System.out.println(person); } // ソート結果 // Person{age=20, name='John'} // Person{age=21, name='Jane'} // Person{age=21, name='Sara'} // Person{age=35, name='Greg'} それでは解説です。 重要なのは Person オブジェクトの大小比較の方法を定義する部分です。 ここでは、compare メソッドの実装の決まりに従うと、 2 つの Person オブジェクト p1, p2 が引数 p1 が p2 より 小さい とする場合は 負の整数 を返す p1 が p2 より 大きい とする場合は 正の整数 を返す 両方が 等しい 場合は 0 を返す ような処理にする必要があります。 また、並べ方は「まず年齢順で並び替え、年齢が同じ時は名前順で並び替える」というルールですので、Person の大小関係と compare メソッドで返す値の対応は以下のようになります。 p1 の年齢が p2 の年齢より小さければ p1 は p2 より 小さい ( 負の整数 を返す) p1 の年齢が p2 の年齢より大きければ p1 は p2 より 大きい ( 正の整数 を返す) もし年齢が同じなら、 p1 の名前が p2 の名前より小さければ p1 は p2 より 小さい ( 負の整数 を返す) p1 の名前が p2 の名前より大きければ p1 は p2 より 大きい ( 正の整数 を返す) 名前の大小も同じなら、 p1 と p2 の大小は 同じ ( 0 を返す) 上記のコードの実装では 1,2 は年齢差を返すことで実現しています。 3,4,5 は String クラスに用意された compareTo()メソッドを使って実現しています。 なお、Comparatorのcompareメソッドをオーバーライドする部分に関して、 ラムダ式 を使って処理だけを直接引数に渡すことも可能です。 Collections.sort(people, (p1, p2) -> { int ageDiff = p1.ageDifference(p2); if (ageDiff != 0 ) { return ageDiff; } else { int nameDiff = p1.getName().compareTo(p2.getName()); return nameDiff; }}); ※ 補足 compareTo()は String クラスに用意された 2 つの文字列を辞書的に比較するメソッド。 Comparable インタフェースの実装であり、これも、「2 つの引数をとり、 第 1 引数が第 2 引数より小さいとする場合は負の整数、両方が等しい場合は 0、第 1 引数が第 2 引数より大きいとする場合は正の整数を返す」ように実装されている。 (参考: Comparable インタフェースの compareTo メソッド ) Collections.sort のデメリット コードを見ただけでは何をしているか分かりにくい 上の実装のようなコードを理解するには、Comparator インタフェースの compare メソッドをどのように実装するかを知っている必要があります。さらに、正の整数を返すのか負の整数を返すのか常に覚えておくことはなかなか大変です。しかもそのような処理を書く必要があるのでコード自体も長く読みづらいものににってしまいます。 元のリストが破壊されてしまう このデメリットはとても重要です。 Collectons の sort メソッドは、ソートしたいリストの要素を直接並び替えています。プログラミングの世界では、このようにオブジェクトを直接変更するようなメソッドは破壊的メソッドと呼ばれます。破壊的メソッドを使うときは特に注意が必要です。それは、オブジェクトを直接変更してしまうと、後でまたそのオブジェクトを利用する際にソートされているのかされていないのかなどを意識しなければならず、処理を追うのが大変になりバグが混入しやすくなるからです。そのため、元のオブジェクトは変更せず、処理結果の新しいオブジェクトを返すような非破壊的メソッドを利用することが好ましいと言えるでしょう。 Stream を使ったソート それでは Stream を使って見やすくかつ簡潔に記述できるソート方法を解説していきます。 ここまで Collections を使ったソートを説明してきましたが、「Collections を使うソートは大変だな」と感じていただければそれで大丈夫です。 Stream はデータの集まりに対して、さまざまな処理(ソートや絞り込み、各データに対する処理など)を簡潔に記述できるようにするインタフェースです。 Stream を使うことで、正の整数 or 負の整数 or 0 を返す処理(compare メソッドの実装)を意識しなくても柔軟なソートができるようになります。 もちろん今まで通り、 3 種類の整数を返す処理を書いてソートすることもできます。 ここでは、『人オブジェクト』に対して、これまで通り 3 種類の整数を返す処理を Stream を使って書くところから始め、コードを改良していきながら、最後に、compare メソッドの実装を意識しなくてもソートできるような方法を紹介します。 Stream を使った単純なソート Stream を使った『人オブジェクト』のソートに行く前に、数値のように要素の大小関係が明らかなものをソートする方法について触れておきます。 List<Integer> numbers = Arrays.asList( 5 , 4 , 8 , 3 , 1 ); List<Integer> sortedNumbers = numbers.stream().sorted().collect(toList()); Stream でソートをする場合は sorted メソッドを使用します。 大小関係が明らかな場合は、引数なしで使うことで自然順序でソートできます。 また、これは非破壊的メソッドなので、ソート結果を新しい変数に格納しています。 collect(toList()) は sorted メソッドの戻り値型が Stream なので型を List に戻しているだけです。 また、 Integer は Comparable インタフェースを実装している(自然順序が定義されている)ので、以下のように、 naturalOrder() や reverseOrder() を使用して昇順、降順にすることもできます。 // 昇順 List<Integer> sortedNumbers = numbers.stream().sorted(Comparator.naturalOrder()).collect(toList()); // 降順 List<Integer> sortedNumbers = numbers.stream().sorted(Comparator.reverseOrder()).collect(toList()); ※Person クラスが Comparable インタフェースを実装していれば、同様に naturalOrder() や reverseOrder() を使用できます(今回は Comparable は実装していません)。 Stream を使った『人オブジェクト』のソート それでは Stream を使った『人オブジェクト』のソートを解説していきます。 3 種類の整数を返す処理でソート Comparator インタフェースの compare メソッドを実装して大小関係(比較方法)を定義するのはこれまでと同じです。 先ほどの繰り返しになりますが、「2 つの引数をとり、 第 1 引数が第 2 引数より小さいとする場合は負の整数、両方が等しい場合は 0、第 1 引数が第 2 引数より大きいとする場合は正の整数を返すような処理」を渡してあげます。 年齢でソート // Comparatorはラムダ式を使って処理だけを直接渡す List<Person> sortedPeopleByAge = people.stream().sorted((person1, person2) -> person1.ageDifference(person2)).collect(toList()); 名前でソート List<Person> sortedPeopleByName = people.stream().sorted((person1, person2) -> person1.getName().compareTo(person2.getName())).collect(toList()); 大小関係が明らかでない場合は、sorted メソッドの引数に Comparator を入れます( ラムダ式 で入れています)。 Collections のソートと比較して、非破壊的メソッドになっているのは良いことですが、どんな整数を返すか意識する必要があるので、まだ、それほどメリットが感じられません。次は comparing メソッドを使って改良していきます。 (参考: Stream クラスの sorted メソッド ) comparing によるキーの指定だけでソート comparing メソッドは、ソートに使うキーを返す関数を受け取り、そのキーで大小比較する Comparator を返します。 例えば、「Person を受け取って Person の name を返す関数」を受け取ると、Person の name でソートする Comparator を返すことができます。 つまり、「名前の大小関係を使う」ということを指定してあげれば、「3 種類の整数を返す Comparator 」を返してくれます。 言い換えれば compare メソッドを実装した Comparator をキーの指定だけで作ってくれるとても便利なやつです。 List<Person> sortedPeopleByName = people.stream().sorted(comparing((Person person) -> person.getName())).collect(toList()); 3 種類の整数を返す処理ではなく、ソートするキーを返す処理を渡すだけになり、どんな整数を返すのかを考えることが無くなりました! キーを返す処理自体を定数としてやるとコードも見やすくなります。 final Function<Person, String> byName = person -> person.getName(); final Function<Person, Integer> byAge = person -> person.getAge(); List<Person> sortedPeopleByName = people.stream().sorted(comparing(byName)).collect(toList()); List<Person> sortedPeopleByAge = people.stream().sorted(comparing(byAge)).collect(toList()); メソッド参照を使うとさらに簡略化できます。 List<Person> sortedPeopleByName = people.stream().sorted(comparing(Person::getName)).collect(toList()); List<Person> sortedPeopleByAge = people.stream().sorted(comparing(Person::getAge)).collect(toList()); ここまで見やすく簡略化できると、Stream の機能を使わない理由がないのがわかってくるのではないでしょうか。 正の整数を返すんだったかな?負の整数を返すんだったかな?なんて迷うこともなく、コードも記述しやすく理解しやすいものになりました。 (参考: Comparator インタフェースの comparing メソッド ) 複数のキーでソート 最後に、年齢で比較した後に名前で比較して『人オブジェクト』をソートしてみます。 Stream を使うとこの処理も非常に簡単に書けます。comparing に続けて thenComparing メソッドを使うだけです。 List<Person> sortedPeopleByAgeAndName = people.stream().sorted(comparing(Person::getAge).thenComparing(Person::getName)).collect(toList()); 序盤に紹介した、 comparing メソッドの実装を自分で書いて Collections.sort を使ってソートしたコードと比較すると、非破壊的メソッドになりコードも非常にシンプルでわかりやすいものになっていますね。 ソートするなら Stream が圧倒的に便利です。 (参考: Comparator インタフェースの thenComparing メソッド ) 最後に 今回は Stream を使って簡潔にソートをする方法を、従来の Collections を使用した方法と比較して解説しました。 これからソートを使う人も、これまで Collections でソートをしていた人も、ぜひ Stream を使ってシンプルでわかりやすいコードで実装してみてください! 参考書籍 Java による関数型プログラミング Java8 ラムダ式と Stream   エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 https://rakus.hubspotpagebuilder.com/visit_engineer/ rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
弊社で毎月開催し、 PHP エンジニアの間で好評いただいている PHP TechCafe。 2022年5月のイベントでは「静的解析」について語り合いました。 弊社のメンバーが事前にまとめてきた静的解析ツールやその使い方の情報にしたがって、他の参加者に意見を頂いて語り合いながら静的解析について学びました。 今回はその内容についてレポートします。 rakus.connpass.com 静的解析とは 一般的な使い方 編集中コードの検証 CIに組み込む 実行時の型検査について PHPDocを書かないと型が通らなくなる? テストコードを静的解析の対象に入れるか? PSRとの関係性 代表的なPHP静的解析ツール PHPMD PHP_CodeSniffer (phpcs) PHPStan Psalm PhpStorm PHPコマンドによる文法チェック 編集後記 静的解析とは Wikipedia からの引用が紹介されました。 コンピュータのソフトウェアの解析手法の一種であり、ファイルを実行することなく解析を行うこと。 ソースコード に対して行われることが多く、少数ながらオブジェクトコードに対して行う場合もある。 ja.wikipedia.org 具体例として、 PHP の ソースコード に対してプログラムを実行せずに解析し、問題点を検出するイメージです。 一般的な使い方 今回は以下の二つを挙げて、紹介されました。 編集中コードの検証 IDE を利用し、コーディング中に静的解析を行うことをイメージして紹介されました。 例として「 PHP 文法の誤りを表示」「不適切コードの指摘」「コード補完」を挙げられていました。 その際に、次のような様々な意見がありました。 PHPerならPhpStormを使用していることが多いため、恩恵は受けていると思う。 コードを書いている際に、下に赤い線で表示されている。 コンパイル しない言語で作る場合、実行時エラーとなる前に気づけるのは、非常に心強い味方となる。 CIに組み込む コードを定期的/自動的に静的解析を行うことをイメージして紹介されました。 具体例としては、以下の説明がありました。 GitにPushした際に自動的に解析を行い、不適切なコードやルール違反を指摘する。 静的解析の実行をGit hooksに組み込んでいる場合もある。 GitにPushし、編集したコードで警告が検出されれば、Pushを拒否するようにも出来る。 PhpStormでコミットする際に、チェックを走らせる事や、自分で選んだコード解析ツールを走らせる事もできる。 メリットとして、以下のような事が紹介されました。 コードレビューの観点が明確になる事で、より有益な話に時間を使えるようになる。 人に指摘されるより気が楽である。 実行時の型検査について 参加者から「実行時の型検査」について考えを聞く質問があり、大変盛り上がりました。 (以下が質問と合わせて貼られたリンクになります。) https://stitcher.io/blog/we-dont-need-runtime-type-checks この記事は PHP の現場で紹介された。 PHP ランタイムが型チェックを行うため、メソッドの戻り値の型を PHP の言語機能でintと記載した場合、実行時にStringを戻り値として返却するとタイプエラーで落ちる。 Docコメントに at return int と記載すれば静的解析のときに弾かれるため、二箇所に return を書く必要があるのは面倒である。 これについては、次のような様々な意見がありました。 自社内でもレビュアーによって意見が割れている。 Docコメントだけでなく、メソッドの戻り値の型を記載して欲しい人。 両方記載は面倒くさいため、言語機能としてサポートされている型はメソッドの戻り値の型を記載し、サポートされていない型はDocコメントに記載する人。 レビューコスト下げるために静的解析を入れているが、意見が割れるため返ってコストが上がってしまっている。 これには PHP の歴史的背景もある。 元々はメソッドの戻り値に型指定ができないため、Docコメントへ記載し、静的解析でチェックする事でしのいできた。 メソッドの戻り値に型指定できるようになった今、「Docコメントで静的解析によるチェック」、「言語仕様として縛りを入れる」のどちらが良いのか? 最終的には以下の方針が挙げられました。 今から新規作成の場合は、言語仕様でもチェックした方が良い。 既存処理への修正の場合、元々静的解析チェックのみで統一されていた箇所は、そのまま「Docコメントに戻り値を記載」で統一でも良い。 しかし、Docコメントはただの文字列であるため、言語仕様で縛れるように少しづつ リファクタリング していく方が良い。 PHPDocを書かないと型が通らなくなる? また、質問者様の考えは以下であったようです。 原則、メソッド戻り値の型宣言は記載する。 Docコメントは ジェネリック スのような必要と判断した場合のみ記載する。 上記以外の基準は、PHPStanでレベルを上げた際に、Docコメントを記載しないとエラーと判定された場合に記載する。 これについては、次のような様々な意見がありました。 PHPStanでしかチェックできないものも多いので、今後方針に悩む箇所が発生しそうだ。 PHPStanでレベルを上げる事によりエラーとなる場合は、他のツールを併用する事で、少しづつPHPStanでメンテする範囲を緩める方法もある。 PHP 言語の型指定が表現豊かではないので、表現豊かにすると実行時にそれだけ解析して処理が重くなるため、Docコメントの方に書いておいたほうが PHP 全体の利益になる。 今は言語仕様が過渡期であるため、 PHP の利点(途中でエラー中断せず最後まで実行)を残すためにノーチェックに出来るオプションが希望されている。 メソッド戻り値の型宣言をCS-Fixerで一括で記載する方法もある。 自動置き換えによる信頼性を疑問視しているので、検出だけ担当するのは良さそう。 テストコードが存在すれば品質は担保できる。 最終的には、チーム皆で話し合って方針を決めて行くのが大事だとまとめられました。 テストコードを静的解析の対象に入れるか? 話の流れから「CIとかで解析を回すときにテストコードは解析対象に入れるか否か」のアンケートが取られました。 このアンケートには、次のような様々な意見がありました。 テストコードを解析するメリットが分からない。 プロジェクト内で PHP の有名なライブラリを確認したが、解析対象になっているものが多かった。 変更部分のみテストできる機能があれば便利である。 CS-Fixerを使用しているが、PHPStanは面倒なので除外にすることが多い。 解析の対象に入れてデメリットは特にないため、基本方針として解析の対象としている。 議論の余地はあるようですが、解析対象として入れるほうが優勢でありました。 PSRとの関係性 PSRとは PHP -FIGが策定している PHP の標準規約集です。 規約は各ルールがほぼ独立しており、好きな規約のみを選んで採用することができます。 www.php-fig.org PSR1とか2とか12とかはコーディング規約に関するものなので取り入れている静的解析ツールも多いのではないか PSR2は現在では非推奨だが、昔からの名残で残っているものもある 代表的な PHP 静的解析ツール PHPMD コードの複雑性を検知してくれるものです。 具体例を挙げると、バグになりそうなコード、最適ではないコード、複雑な表現、未使用のパラメータ・メソッド・プロパティなどを検出してくれるツールです。 これについては、次のような様々な意見がありました。 インストール方法は色々あり、最近だとComposerが便利。直接GtiHubから落とすことも出来る。 コマンドで実行した場合、PHPMDで検出対象のファイルや ディレクト リを指定、結果のフォーマット選択、ルールセット指定の手順である。 ルールセットは、コードサイズや、設計関連ルール、ネーミング、未使用コード検出などのルールが予め定義されている。 xml ファイルを配置し、必要なルールのみ適用、または、不要なルールを削除し、個別ルール(最大値や最小値など)へ変更することも可能である。 実行例 [ root@vg110 core ] # vendor/phpmd/phpmd/src/bin/phpmd test .php text codesize,controversial,design,naming,unusedcode /usr/local/vanguardDev/vanguard/vg-back/core/ test .php:5 CamelCaseMethodName The method test_function is not named in camelCase. /usr/local/vanguardDev/vanguard/vg-back/core/ test .php:5 CamelCaseParameterName The parameter $param_string is not named in camelCase. /usr/local/vanguardDev/vanguard/vg-back/core/ test .php:5 CamelCaseVariableName The variable $param_string is not named in camelCase. phpmd.org PHP _CodeSniffer (phpcs) コーディング規約の違反を検出するライブラリです。 PSRや PEAR などの様々なコーディング規約を指定して検査を実施してくれます。 これについては、次のような様々な意見がありました。 独自の規約を追加することも可能である。 インストール方法は色々あり、Composerや GitHub からなど、好みの方法で導入できる。 コーディング規約の違反を自動で修正するphpcbfも付属している。 全て修正する事は出来ず、修正出来た物も目視チェックは必要である。 完全に信用する訳ではなく、phpcsの指摘があるファイルをユーザに通知し、修正は手動で行う運用をしている。 phpcbfは結構正確だが、phpcsに問題がある。 改行やインデントについて、コード上は正常であっても、CS-Fixerがエラーと判定するケースがたまにある。 実行例 $ phpcs /path/to/code/myfile.php FILE: /path/to/code/myfile.php -------------------------------------------------------------------------------- FOUND 5 ERROR ( S ) AND 1 WARNING ( S ) AFFECTING 5 LINE ( S ) -------------------------------------------------------------------------------- 2 | ERROR | Missing file doc comment 20 | ERROR | PHP keywords must be lowercase; expected " false " but found | | " FALSE " 47 | ERROR | Line not indented correctly; expected 4 spaces but found 1 47 | WARNING | Equals sign not aligned with surrounding assignments 51 | ERROR | Missing function doc comment 88 | ERROR | Line not indented correctly; expected 9 spaces but found 6 -------------------------------------------------------------------------------- コーディング規約の指定 # インストールされているコーディング規約を確認 $ phpcs -i The installed coding standards are MySource, PEAR, PSR1, PSR12, PSR2, Squiz and Zend # コーディング規約を指定して実行(デフォルトはPEAR) $ phpcs --standard=PSR12 /path/to/code/myfile.inc # デフォルトのコーディング規約を変更 $ phpcs --config-set default_standard PSR12 規約のカスタマイズ phpcs. xml ファイルを設置して独自のコーディング規約を設定できる。 <? xml version = "1.0" ?> <ruleset name = "Custom Standard" > <rule ref = "PSR12" > <!-- "PSR12" の中で除外するルール --> <exclude name = "Generic.Files.LineLength" /> </rule> <!-- 追加するルール --> <rule ref = "PEAR.WhiteSpace.ObjectOperatorIndent" /> <!-- 除外するファイル・ディレクトリ --> <exclude-pattern> node_modules/ </exclude-pattern> </ruleset> github.com PHPStan こちらも同じくComposerやDockerから利用可能です。 PHARからもダウンロード可能です。 ただし、Composerが無いとPHPStanの 拡張機能 は使えません。 解析の厳密さはオプションで変更可能で、PHPStanの場合はレベル0から9で設定可能です。 レベル0が一番ゆるく、レベル9が最も厳密となっている レベル0は基本的なチェックで、PSRと同等のチェックレベル レベル9では、混合型(mixed)についても厳密であるレベル(混合型(mixed)は、別の混合型(mixed)に渡す操作しか許可されない)になる PHPStanの公式に記載がありますが、以下の理由から使用方法はレベル0から順番に対応していくのが正攻法のようです。 初めからレベル9を設定すると、エラー件数が膨大となり、何から手を付けたらいいか分からなくる。 上位のレベルでエラーを検知した際は、下位のレベルで検知されるエラーも合わせて修正を行わないと、エラーは解消されない 歴史の長いプロジェクトでは、レベル0の設定でも多くのエラーが検出されます。 全ての検出されたエラー対応が困難な場合は、ベースラインの設定を推奨します。 ベースラインを設定することにより、以下のようなことが出来ることが紹介されました。 ある時点で検出したエラー内容を基準とし、それ以降の静的解析の実行で、基準としたエラー内容を報告しないように出来る。 既存コードで検出されているエラーを除外出来るため、新しいコードと変更されたコードで検知されたエラーのみに注力することが出来る。 カスタムルールも設定できるようになっており、 phpstan-rules と phpstan-strict-rules を使用して拡張することが出来る。 これについては、次のような様々な意見がありました。 レベル5からレベル6の間が深い河である レベル6は「タイプヒントの欠落を表示」であるため、クリア難易度が高い ベースラインの概念があることは有難い 別のツールでPHPStanのベースラインと同様の事を行ったが、非常に辛かった ベースラインの概念は他ツールでは、Psalmにもある サイボウズ さんでは「ベースラインを自動実行する」取り組みを行っていて面白そう(※) phpstan.org ※ 情報元の紹介はありませんでしたが、記事化にあたって調べたところ参考になるスライドがありました。  ツールはPHPStanではないですが、適応出来そうです。 効果的な静的解析の CI導入パターンを求めて / Great static analysis with CI - Speaker Deck Psalm こちらもPHPStanと同様で、厳密さをレベルで調節できます。 ただし、レベルの強弱がPHPStanと逆になっており、レベル1が最も厳しく、レベル8が一番ゆるい設定になっています。 良い点として、次のように紹介されました。 検知された違反ルールがなぜ不適切なのか理由が解説されるため、納得感を得やすくなっている。 これがなんで悪いの? と思うときがあるが、理解ができると直すモチベーションも得られるのではないか。 例 psalm.dev PhpStorm 編集中に解析を行い、危険な箇所に対して下線で示すか、ハイライトしてくれます。 解析方法は PHP ファイルをPhpStormで開くだけです。 文法の誤りをハイライトし、重要度によってハイライト部分の色が変更されるため見やすい。 プロファイルの編集で解析内容を編集でき、任意の解析を追加する事もできる。 他の解析ツールをインストールし使用すことも可能。 pleiades.io PHP コマンドによる文法チェック 少し本筋とは違いますが、「静的解析を調べる際に、 php -l で文法チェックができることを見つけた。」と紹介されました。 そのため、文法の間違いについては、静的解析ツールを使用せずにエラー検知する事が出来ます。 これについては、次のような様々な意見がありました。 php -l で静的解析できることを初めて知った。 静的解析かと言われると疑問がある。一応解析は行っているので意味は合っている? 全ファイルを対象に php -l を実行したことが何度かある。 おそらく全ファイルに対して一括置換のような処理を実行したタイミング。 または、 PHP のメジャーバージョンアップ後に粗探しとして調査するタイミング。 PHP のバージョンアップ後に一旦実行し、エラー検知した場合は早急に対応が必要であるため。 編集後記 以上、静的解析の概要と代表的なツールについて取り上げました。 PHP TechCafeでは今まで取り上げることがなかった話題でしたので、主催者/参加者ともに盛り上がりを見せていました! 今後も静的解析の活用方法や、新たなニュースに着目していきたいと思います! 「 PHP TechCafe」では今後も PHP に関する様々なテーマのイベントを企画していきます。 皆さまのご参加をお待ちしております。 connpass.com エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
技術広報の yayawowo です。 今回は、 Linux 上でファイルや ディレクト リ内容を一覧表示する際に利用する、 『ls コマンド』 について紹介します! ls コマンドの基本をはじめ、活用例をコマンドサンプルを交えて説明させていただきます。 【目次】 ls コマンドとは? ls コマンドの使い方 基本書式 ls コマンドのオプション一覧 表示フォーマット関連 出力フォーマット関連 サイズ関連 時間関連 ソート関連 ls コマンドの活用例 Linux関連のおすすめブログ 終わりに ls コマンドとは? lsコマンドは、ファイルや ディレクト リの一覧を表示するためのコマンドです。 ls コマンドの使い方 基本書式 ls コマンドの基本書式は、以下の通りです。 $ ls [ オプション ] [ ファイル/ディレクトリ ] ファイルや ディレクト リの一覧を表示させるには、対象のファイル/ ディレクト リ名を指定する必要があります。 また、ls コマンドには多くのオプションがあります。 以下にまとめておきますので、用途に合わせて使い分けください。 ls コマンドのオプション一覧 表示フォーマット関連 オプション 説明 -l 詳細情報を表示 -o グループ情報以外の詳細情報を表示 -n 所有者/グループ名の代わりにユーザIDとグループIDとし、詳細情報を表示 -a .(ドット)ファイルも含めて表示 -A 「.」「..」以外の.(ドット)ファイルも含めて表示 -d ディレクト リ内容を表示せず、 ディレクト リ名のみを表示 出力フォーマット関連 オプション 説明 -1 リストを1件1行で表示 -m リストをカンマ区切りで表示 -C リストの出力を列(縦)にソート表示 -x リストの出力を行(横)にソート表示 -q 表示不可能な文字を?で表示 -F ファイル/ ディレクト 名の後にタイプ識別子(*/=>@|のどれか)を付けて表示 -p ディレクト リ名の後にのみ、/を付けて表示 サイズ関連 オプション 説明 -k -l と併用し、1KB単位のサイズ形式で表示 時間関連 オプション 説明 -c -l と併用し、ファイル属性の変更時間(ctime)を表示 -u -l と併用し、最終アクセス日を表示 ソート関連 オプション 説明 -S ファイルサイズが大きい順に表示 -t ファイル更新日が新しい順に表示 -v 数字順にソート表示 -r 並び順を反転させて表示 ls コマンドの活用例 前提としまして、 /home 配下に以下 ディレクト リとファイルを準備しております。 /home  ┗ sample  ┗ sample2  ┗  hoge .txt  ┗ hoge2.txt これを使い、ls コマンドの活用例をご紹介します! 詳細情報を表示(-l) localhost:/home# ls -l total 8 -rw-r--r-- 1 root root 0 Sep 13 09:12 hoge.txt -rw-r--r-- 1 root root 0 Sep 13 09:40 hoge2.txt drwxr-xr-x 2 root root 37 Sep 13 09:12 sample drwxr-xr-x 2 root root 37 Sep 13 09:12 sample2 所有者/グループ名の代わりにユーザIDとグループIDとし、詳細情報を表示(-n) localhost:/home# ls -n total 12 -rw-r--r-- 1 0 0 0 Sep 13 09:12 hoge.txt -rw-r--r-- 1 0 0 0 Sep 13 09:40 hoge2.txt drwxr-xr-x 2 0 0 37 Sep 13 09:12 sample drwxr-xr-x 2 0 0 37 Sep 13 09:12 sample2 .(ドット)ファイルも含めて表示(-a) localhost:/home# ls -a . .. hoge.txt hoge2.txt sample sample2 リストを1件1行で表示(-1) localhost:/home# ls -1 hoge.txt hoge2.txt sample sample2 ディレクト リ名の後にのみ、/を付けて表示(-p) localhost:/home# ls -p hoge.txt hoge2.txt sample/ sample2/ ファイルサイズが大きい順に表示(-S) ※ -l と -S の複数オプション利用のため、コマンド実行時は -lS と定義しています。 localhost:/home# ls -lS total 8 drwxr-xr-x 2 root root 37 Sep 13 09:12 sample drwxr-xr-x 2 root root 37 Sep 13 09:12 sample2 -rw-r--r-- 1 root root 0 Sep 13 09:12 hoge.txt -rw-r--r-- 1 root root 0 Sep 13 09:40 hoge2.txt ファイル更新日が新しい順に表示(-t) ※ -l と -t の複数オプション利用のため、コマンド実行時は -lt と定義しています。 localhost:/home# ls -lt total 8 -rw-r--r-- 1 root root 0 Sep 13 09:40 hoge2.txt -rw-r--r-- 1 root root 0 Sep 13 09:12 hoge.txt drwxr-xr-x 2 root root 37 Sep 13 09:12 sample2 drwxr-xr-x 2 root root 37 Sep 13 09:12 sample 並び順を反転させて表示(-r) ※ -l と -t と -r の複数オプション利用のため、コマンド実行時は -ltr と定義しています。 # ファイル更新日順に表示 localhost:/home# ls -lt total 8 -rw-r--r-- 1 root root 0 Sep 13 09:40 hoge2.txt -rw-r--r-- 1 root root 0 Sep 13 09:12 hoge.txt drwxr-xr-x 2 root root 37 Sep 13 09:12 sample2 drwxr-xr-x 2 root root 37 Sep 13 09:12 sample # ファイル更新日順を反転し、表示 localhost:/home# ls -ltr total 8 drwxr-xr-x 2 root root 37 Sep 13 09:12 sample drwxr-xr-x 2 root root 37 Sep 13 09:12 sample2 -rw-r--r-- 1 root root 0 Sep 13 09:12 hoge.txt -rw-r--r-- 1 root root 0 Sep 13 09:40 hoge2.txt Linux 関連のおすすめブログ tech-blog.rakus.co.jp Linux コマンドのまとめ記事です! 本ブログがあれば、 Linux 操作に困らないと思います。 tech-blog.rakus.co.jp Linux 上でエディタを触る機会が多い方向け! vi コマンドの基本的な使い方を目的別にまとめております。 tech-blog.rakus.co.jp Linux 上に存在するログを調査するにあたり、良く用いる文字列検索を行う grep コマンドの記事です。 grep コマンドの中でも、実務でよく使っている検索方法を併せて紹介しています! tech-blog.rakus.co.jp 2つのファイルを比較して違い(差分)を出力するdiff コマンド。 diffコマンドの表示オプションを知りたい方は、是非ご確認ください。 tech-blog.rakus.co.jp Linux 上でファイルや ディレクト リ検索時に利用するfind コマンドについて紹介! find コマンドの基本をはじめ、活用例をコマンドサンプルを交えて説明しております。 終わりに いかがでしたでしょうか? 今回はファイルや ディレクト リの一覧を表示したい際に良く用いる、ls コマンドをご紹介させていただきました。 また、ls コマンドのオプションも今回ご紹介させていただきましたが、利用用途に合わせて使い分けていただくことで業務効率を上げることができます! ls コマンドは、 Linux を触る方にとっては基本のキかと思います。 もし、ls コマンドを触るときに「どのオプション使うんだっけ?」と不安になった方は是非本記事をご参考いただけますと幸いです。 最後までお読みいただきありがとうございました! ◆ その他おすすめブログ ・ sar コマンド【使い方 まとめ】 ・ iptables まとめ【Linux ファイアウォール】 ・ sed コマンド【使い方 まとめ】 ・ Linuxのファイル操作でよく使うLinuxコマンド ・ 初心者のためのawkコマンド ・ 実務で使える!基本的なシェル(Linux)コマンドの話 ~forとsed~ ・ 【Linux】今振り返りたい、プロセスって何? エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
弊社で毎月開催し、 PHP エンジニアの間で好評いただいている勉強会「 PHP TechCafe」。 2022年3月のイベントでは『PHPerのための「Laravel9について語る」』をテーマに語り合いました。 弊社のメンバーがLaravel9の新機能などの情報を元に、他の参加者に意見をいただいて語り合いながらLaravel9について理解を深めました。 今回はその内容についてレポートします。 rakus.connpass.com PHP TechCafeとは PHPerのための「Laravel 9 について語る」 Laravel9の特徴 PHP8対応 LTSが消えた ハイペースなマイナーバージョンアップ Laravel9の新機能や変更点 Symfony Mailer Flysystem 3.x Improved Eloquent Accessors / Mutators Enum Eloquent Attribute Casting Implicit Route Bindings With Enums Forced Scoping Of Route Bindings Controller Route Groups Full Text Indexes / WhereClauses Slot Name Shortcut Checked / Selected Blade Directives whereNot clause Improved Ignition Improved route:list CLI Output アップデートの落とし穴 app/Http/Middleware/TrustProxies.php の修正 $headersの修正 編集後記 PHP TechCafeとは 本題に入る前に「 PHP TechCafe」について軽く説明します。 「 PHP TechCafe」とは弊社が主催しているエンジニア向けのイベントで、エンジニア同士で技術について話し合う憩いの場(カフェ)です。 月に1回開催し、コロナ禍の現在はオンラインで開催しています。 対象者は PHP 入門の初級エンジニアからシニアエンジニアを幅広くカバーし、学びの場を提供してエキスパートまでの自己成長を支援することを目的にしています。 「 PHP TechCafe」は以下の3部構成です(日によって変わることもあります)。 ライトニング トーク (LT) PHPer's NEWS 特集 2022年3月の特集は『PHPerのための「Laravel 9 について語る」』をテーマに開催いたしました。 今回はその中で紹介された内容や盛り上がったポイントをレポートします。 PHPerのための「Laravel 9 について語る」 Laravel9の特徴 まずはお約束のLaravel9の特徴からです。 PHP8対応 PHP8に対応し、8未満には対応しなくなりました。 LTSが消えた どんどんバージョンを上げていきましょう!、という意味かもしれませんね。 ハイペースなマイナーバージョンアップ Laravel9は、短いスパンで次々とマイナーバージョンアップを重ねていることにも注目が集まり、話題となりました。 マイナーバージョンアップで新機能がいくつも追加されています。 意外と使えそうな機能もよくあるので、新機能を使いたくなったら上げなきゃいけないですね。 Laravel9の新機能や変更点 Symfony Mailer Laravel標準の メーラー がSwift Mailerから Symfony Mailerに変更されました。 そもそもSwift Mailerってメンテナンスが止まっているのでLaravelもこちらに乗り換えたようです。 結構互換性の無いものもあるので、しっかり見て変更しましょう。 インターフェースも変わってしまったんですね。Classを呼んでるところだけ置き換えたらOKという感じでもないですね。しっかり置き換えないといけない。 Sending Emails with Mailer (Symfony Docs) Flysystem 3.x Storage ファサード によって提供されており、ファイル操作系処理を強化するFlysystemがバージョンアップしました。 S3とか FTP などを利用している場合はドライバのアップデートが必要です。 挙動も変わっているんですよね。PutやWrite、Writestreamなどを使うとデフォルトでファイルを上書きするようになるので、注意しないといけないです。 存在しないファイルを指定すると以前はNullが返ってきていましたが、例外が返ってくるようになりました。 File Storage Abstraction for PHP - Flysystem Improved Eloquent Accessors / Mutators これはEloquentのモデルについてです。 Laravel9 以前 <?php public function getNameAttribute ( $ value ) { return strtoupper ( $ value ) ; } public function setNameAttribute ( $ value ) { $ this -> attributes [ 'name' ] = $ value ; } ↑ モデルにアクセサーとミューテタに プレフィックス 付きのメソッドを定義する必要がありました。 Laravel9 <?php use Illuminate\Database\Eloquent\Casts\Attribute; public function name () : Attribute { return new Attribute ( get : fn ( $ value ) => strtoupper ( $ value ) , set : fn ( $ value ) => $ value , ) ; } ↑ プレフィックス なしのメソッドに戻り値の型を指定(Attribute)することで、アクセサーとミューテタが定義可能となりました。 ルーティング 9.x Laravel Enum Eloquent Attribute Casting PHP8.1以上で稼働させている場合のみ動作して、モデルに挿入する値を Enum 型でキャスト可能にします。 <?php use App\Enums\ServerStatus; /** * The attributes that should be cast. * * @var array */ protected $ casts = [ 'status' => ServerStatus :: class , ] ; Eloquent:ミューテタ/キャスト 9.x Laravel Implicit Route Bindings With Enums ルートパラメータを Enum 型で指定することができます。 型に一致しないパラメータが指定されたら、404が返されます。 Enum の定義 <?php enum Category : string { case Fruits = 'fruits' ; case People = 'people' ; } ルーティングの記載 <?php Route :: get ( '/categories/{category}' , function ( Category $ category ) { return $ category -> value ; }) ; Enum が使えるようになったから、こういうところにも使っていこうっていうことですかね。 どこを見たら良いかわかりやすいですね。 404にしてくれるのがありがたい。無理やり動かすのは流石につらいので。 ルーティング 9.x Laravel Forced Scoping Of Route Bindings 親のモデルと子のモデルを使用してRoute model bindingを行いたい場合、子のモデルにはカスタムキーを使用する必要がありました。 Laravel9 以前 <?php use App\Models\Post; use App\Models\User; Route :: get ( '/users/{user}/posts/{post:slug}' , function ( User $ user , Post $ post ) { return $ post ; }) ; それが、scopeBindings()を使用することで、カスタムキーなしでも子のモデルに対してRoute model bindingを行えるようになりました。 Laravel9 <?php use App\Models\Post; use App\Models\User; Route :: get ( '/users/{user}/posts/{post}' , function ( User $ user , Post $ post ) { return $ post ; }) -> scopeBindings () ; Route model bindingとは、例えばこのコードの場合、RouteパラメータのところにUserやPostやモデル名を指定しています。UserのところにID1が入ったとしたらID1のUserのモデル インスタンス を自動的に取ってきてくれるというものです。 今まではカスタムキーで”post:slug”を定義する必要があったのですが、それがLaravel 9からScope Bindingを使えば不要となり、シンプルに書きやすくなったようですね。 ルーティング 9.x Laravel Controller Route Groups 全てのルートに共通のコントローラをグループとして定義できるようになりました。 Laravel8 <?php # 何度もController名を書かないといけない use App\Http\Controllers\OrderController; Route :: get ( '/orders/{id}' , [ OrderController :: class , show ]) ; Route :: post ( '/orders' , [ OrderController :: class , store ]) ; Laravel9 <?php use App\Http\Controllers\OrderController; Route :: controller ( OrderController :: class ) -> group ( function () { Route :: get ( '/orders/{id}' , 'show' ) ; Route :: post ( '/orders' , 'store' ) ; }) ; コントローラごとにグループ分けができるようになりました。 この変更にはこんな声がありました。 ヤンチャな実装する人だったら、まとまりを無視して変なところに定義を書いたりすることがありますが、Laravel9だとそこは強制されるのでヤンチャできなくなりますね。 概念としてコントローラが上になったような気がして、個人的にはちょっと嫌だなって思いますね。コントローラがルートを決めたんじゃないかというニュアンスになるので。 ルートとコントローラが密結合になったんじゃないかという印象を持ちました。ここまでやるならそもそも定義書かなくてよくない?という感じもしますね。 ルーティング 9.x Laravel Full Text Indexes / WhereClauses 指定した列に FULLTEXT INDEX を作成できます。※ MySQL か PostgreSQL <?php $ table -> text ( 'bio' ) -> fullText () ; FULLTEXT INDEX がある列に対して、WHERE句を作成することもできます。 <?php $ users = DB :: table ( 'users' ) -> whereFullText ( 'bio' , 'web developer' ) -> get () ; これすっごくありがたいです。どデカいテキストの部分一致検索みたいなやつは、 巨大掲示板 とかになってくると Elasticsearch にするとかでないと対応できなかったんです。 PostgreSQL にしろ MySQL にしろテーブルとかインデックスの型の定義がすごく独特で大変なんです。しかも標準 SQL に定義されていない機能なので正直ダルいんですよ…。だから欲しかった人は本当に欲しかったものだと思います。 今まではCreate Indexとか SQL を直書きしないと駄目ですよね。それを検索するときもwhereじゃなくてwhereRawとか使って SQL 直書きするしかなかったんですよ。それが公式にサポートされたから作れるようになったんですね。 データベース:クエリビルダ 9.x Laravel Slot Name Shortcut Blade関連ですね。 X-slotタグを短く書けるようになりました。 Laravel9 以前 <x-alert> <x-slot name = "title" > Server Error </x-slot> </x-alert> Laravel9 < x-slot : title> Server Error </x-slot> これはサッと読めるようになるので、どんどん使っていきたいですね。   Bladeテンプレート 9.x Laravel Checked / Selected Blade Directives こちらもBlade関連。 @checked  チェックボックス をONに指定できる <?php < input type = "checkbox" name = "active" value = "active" @checked ( old ( 'active' , $ user -> active )) /> @selected セレクトボックスにてデフォルトで選択されている項目を指定できる <?php < select name = "version" > @ foreach ( $ product -> versions as $ version ) < option value = "{{ $ version }}" @selected ( old ( 'version' ) == $ version ) > {{ $ version }} </ option > @ endforeach </ select > @checkedって書いていたらそこの チェックボックス をオンに出来ますよとか、@selectedにしたらデフォルトで選択されている項目を指定できます。今まで 三項演算子 で書いていたものがBladeで書けるようになって、痒いところに手が届くようになりました。 Bladeテンプレート 9.x Laravel whereNot clause クエリビルダでずっとサポートされていなかった、whereNotがようやく使えるようになりました。 whereNotは何回かリジェクトされて9.3でやっと取り込まれた経緯があるそうです。 できることなら肯定形で書きたいです。でも SQL の構文として存在するものはサポートしてほしい気はしますね。今までそれをあえて入れなかったのは、否定形を入れずに綺麗なものを目指すんだという強い意思があったのかもしれないですね。 SQL の構文としてはあるけど、Laravelには無いから今回取り入れたという感じですかね。あえて書きたいケースもありますし。他のすべてのメソッドにはNotがあるけれど、whereにだけ無いと。 データベース:クエリビルダ 9.x Laravel Improved Ignition 開発中の例外発生時などに表示されるIgnitionが新しくなりました。 ダークテーマや「エディタで開く」を選べるようになりました。 リリースノート 9.x Laravel Improved route:list CLI Output route:listの CLI が見やすくなりました。 最近 CLI の見やすくなるアップデートが割と多いですね。 本当に見やすくなりました。ただ一方で PHPUnit Printerに外部ライブラリを入れて綺麗にしていた人は一気に全部崩れたみたいです。なので外して公式にし直すというのがウチではありました。 以前は色も何もついてなくて、”…”もついてなくて、縦バーで区切ってましたね。 リリースノート 9.x Laravel アップデートの落とし穴 アップデートガイドのところでここの PHP ファイルだけ開いて修正してね、ということです。ここだけ手作業ということで、ハマりそうですね。 app/Http/Middleware/TrustProxies. php の修正 変更前 use Fideveloper\Proxy\TrustProxies as Middleware 変更後 use Illuminate\Http\Middleware\TrustProxies as Middleware $headersの修正 変更前 protected $headers = Request::HEADER_X_FORWARDED_ALL; 変更後 protected $headers = Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_POST | Request::HEADER_X_FORWARDED_PROTO | Request::HEADER_X_FORWARDED_AWS_ELB ; Composerをアップデートしてもダメで、Bootstrapのキャッシュを消さなきゃいけないのでこの作業が必要になるようです。 ここはつまづきますね。「キャッシュ周りでアップデートしたのに何で古い方を読みにいってるの?」ってことが起こってました。 Upgrade Guide - Laravel - The PHP Framework For Web Artisans 編集後記 メジャーバージョンアップだけではなく、マイナーバージョンアップでも次々に機能追加がされたりとさらに開発が活発化している印象でした。 LTSがなくなったのは我々開発者としては痛いところですが、これは長期サポートのコストをLaravelの開発をどんどん前に進めることに充てるというアグレッシブな思想があるからかもしれませんね。 ここでは語りつくせない変更もまだまだあるので、リリースノートは要チェックです。 今後もLaravelの進化から目が離せません! 「 PHP TechCafe」では今後も PHP に関する様々なテーマのイベントを企画していきます。 皆さまのご参加をお待ちしております。 connpass.com エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
はじめに 皆さんこんにちは、開発課のthree_yagiです。 現在の業務では不具合などが発生したときの原因調査を担当することが多く、本番環境のログの調査をよく行っています。 Linux 上に存在するログを調査するにあたって、必須ともいえるのが文字列検索を行う grep コマンドです。 こちらの記事では、 grep コマンドについて私が実務でよく使っている検索方法と併せて紹介していきます。 目次 はじめに 目次 grep コマンドの基本 基本構文 よく利用するオプションと正規表現 オプション 正規表現 利用例(基本編) 基本の検索 AND検索 OR検索 NOT検索 大文字と小文字を区別しないで検索 マッチした行数を表示 マッチした行のうち〇行だけ表示 マッチした行の前後の行も表示する 正規表現で様々な条件で検索する 利用例(応用編) grepした文字をハイライト表示 圧縮ファイルをgrepする grepコマンド まとめ   grep コマンドの基本 grep は 検索対象のファイルから指定した文字列を含む行を表示する Linux コマンドです。 正規表現 とオプションを駆使することで様々な条件での検索が行えます。 基本構文 $ grep [オプション] 検索文字列 対象ファイル よく利用するオプションと 正規表現 実際によく利用しているオプションについて記載します。 これらを使いこなせれば一通りの検索はできるかなと思います。 オプション オプション 説明 -E 拡張正規表現 (ERE)を利用する ※このオプションなしでも 正規表現 の「. * ^ $ [ ]」は利用可能 -e [検索文字列] オプションの引数として検索文字列を指定する このオプションを複数回使用することでOR検索が可能 -v 結果を反転する。検索文字列を含む行以外を表示 -i 検索文字列の大文字と小文字を区別しない -c マッチした行ではなく、マッチした行数を表示 -m [数字] [数字]行分だけ表示する -B [数字] マッチした行の前 [数字] 行を表示 -A [数字] マッチした行の後 [数字] 行を表示 -C [数字] マッチした行の前後 [数字] 行を表示 -h 出力する行の前にファイル名を付けないようにする -n 頭にそのファイル内での行数を表示 正規表現 正規表現 を利用することで柔軟な検索ができるようになります。 拡張正規表現 の列が「〇」の 正規表現 はオプションで「-E」を指定する必要があります。 正規表現 意味 拡張正規表現 . 任意の 1 文字 * 直前の 1 文字または パターンが 0 回以上繰り返す ^ 行の先頭を表す $ 行の末尾を表す [ ] 括弧内の任意の 1 文字が存在する ( ) パターンのグループ化 〇 + 直前の 1 文字 または パターンが 1 回以上繰り返す 〇 ? 直前の 1 文字 または パターンが 0 回または 1 回だけ存在 〇 {n} 直前の 1 文字 または パターンが n 回繰り返す 〇 | 2 パターンのうちどちらか片方 〇 利用例(基本編) 実際の利用例を見ながら利用方法について確認してみましょう。 検索対象のテストファイル(test.txt)には 都道 府県がローマ字で記載されたファイルを使用しています。 # テスト用ファイル $ cat test .txt hokkaido aomori iwate miyagi akita yamagata ︙ miyazaki kagoshima okinawa 基本の検索 まずは単純に指定した文字列を含む行を表示してみます。 # 【検索条件】'yama' を含む行を表示 $ grep ' yama ' test .txt yamagata toyama yamanashi wakayama okayama yamaguchi AND検索 grep の結果を |(パイプ) でつなぐことで1つ目の grep の検索結果に再度 grep をかけることになり、AND検索が可能です。 # 【検索条件】'yama' と 'oka'を含む行を表示 $ grep ' yama ' test .txt | grep ' oka ' okayama OR検索 OR検索はオプションの「-e」を使って検索文字を複数指定する方法と、 正規表現 を利用する方法があります。 正規表現 を利用する場合は 拡張正規表現 の「|」を使用するので、オプション「-E」を指定する必要があります。 どちらも結果は同じになるのでお好きな方を利用してください。 # 【検索条件】'yama' または 'oka' を含む行を表示 # 「-e」を使ってOR検索 $ grep -e ' yama ' -e ' oka ' test .txt # 正規表現でOR検索 $ grep -E ' yama|oka ' test .txt # 結果は同じ yamagata toyama yamanashi shizuoka wakayama okayama yamaguchi fukuoka NOT検索 ○○を含む行以外を検索したい場合は、検索結果を反転する「-v」オプションを利用します。 #【検索条件】 'yama'を含まない行を表示 $ grep -v ' yama ' test .txt hokkaido aomori iwate miyagi akita fukushima ibaraki ⁝ 複数指定する場合 #【検索条件】 'yama' と 'oka'を含まない行を表示 # OR検索の結果を「-v」で反転させればどちらも含まない行を表示できます $ grep -v -e ' yama ' -e ' oka ' test .txt $ grep -v -E ' yama|oka ' test .txt ( 結果省略 ) 大文字と小文字を区別しないで検索 デフォルトでは文字の大文字と小文字を区別した状態で検索を実行します。 大文字と小文字を区別せずに検索する場合は「-i」オプションを利用します。 # オプションなしだと'Yama'を含む行しか対象とならないのでいずれの行も出力されません $ grep ' Yama ' test .txt # オプションありだと'yama'も対象となるので結果が出力されます $ grep -i ' Yama ' test .txt yamagata toyama ⁝ マッチした行数を表示 「-c」オプションを用いることで検索結果の行ではなく行数が表示されます。 #【検索条件】'yama'を含む行の合計の行数を表示 $ grep -c ' yama ' test .txt 6 マッチした行のうち〇行だけ表示 「-m」オプションで結果を表示する行数を指定できます。 #【検索条件】'yama'を含む行のうち頭から2行分だけ表示 $ grep -m 2 ' yama ' test .txt yamagata toyama マッチした行の前後の行も表示する 「-B」「-A」「-C」オプションを利用することでマッチした行の前後の行も表示できます。 「-B」「-A」で前と後それぞれの表示する行数を指定でき、「-C」で前後まとめて行数を指定できます。 ログを調査する際にはよく使うオプションです。 #【検索条件】 'tokyo' を含む行を前後1行も含めて表示 # 「-B」「-A」で前後それぞれ指定 $ grep -B 1 -A 1 ' tokyo ' test .txt # 「-C」でまとめて指定 $ grep -C 1 ' tokyo ' test .txt chiba tokyo kanagawa #【検索条件】 'tokyo' を含む行を前3行,後2行も含めて表示 $ grep -B 3 -A 2 ' tokyo ' test .txt gunma saitama chiba tokyo kanagawa niigata 正規表現 で様々な条件で検索する #【検索条件】'〇a〇a〇a'という文字列を含む行を表示 # '.'は任意の1文字 $ grep ' .a.a.a ' test .txt yamagata kanagawa yamanashi wakayama okayama kagawa nagasaki # こちらも同じ条件での検索となる # '( )' グループ化 # '{n}'直前の文字のn回の繰り返し $ grep -E ' (.a){3} ' test .txt #【検索条件】'a'で始まる行を表示 # `^`は行頭を意味する $ grep ' ^a ' test .txt aomori akita aichi #【検索条件】'a'で始まり先頭以外にも'a'を含む行を表示 # '*'は直前の文字の0回以上の繰り返し # '.'と組み合わせた '.*' は任意の0 or n文字を表す $ grep ' ^a.*a ' test .txt akita 利用例(応用編) grep した文字をハイライト表示 --color=always で検索した文字列に色を付けることができます。 検索結果が大量のときや、 正規表現 で検索していてどこからどこまでがマッチしているか確認したいときなどに便利です。 $ grep --color = always -E ' (.a){3} ' test .txt このように表示されます 圧縮ファイルを grep する ログファイルなどは圧縮された状態で保存されていることが多いかと思います。 圧縮されたファイルに対しては zgrep コマンドを利用することで grep と同じように検索できます。 grep と同じオプションや 正規表現 も利用でき、使用方法としては grep と同じになります。 $ zgrep -i ' Yama ' test .gz grep コマンド まとめ grep コマンドは Linux を利用するにあたって必須ともいえるコマンドです。 使いこなせるようになればファイルの検索などのスピードが劇的にアップします。 今回紹介したのは一部のオプション、 正規表現 となります。 他にも有用なものはたくさんあるのでぜひご自身で調べてみてください。 ◆ Linux の理解をより深めたい方へ以下関連おすすめブログ ・ ls コマンド 【使い方 まとめ】 ・ よく使うLinuxコマンド一覧【最新版】 ・ sar コマンド【使い方 まとめ】 ・ iptables まとめ【Linux ファイアウォール】 ・ sed コマンド【使い方 まとめ】 ・ vi コマンド【使い方まとめ】 ・ Linuxのファイル操作でよく使うLinuxコマンド ・ 初心者のためのawkコマンド ・ 実務で使える!基本的なシェル(Linux)コマンドの話 ~forとsed~ ・ 【Linux】今振り返りたい、プロセスって何?   エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 https://rakus.hubspotpagebuilder.com/visit_engineer/ rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
こんにちは! ラク スでインフラ開発部というところに所属している akiponx です。 今回は CDN の一つ。 AWS が提供しているCloudFrontで WordPress を高速化してみた話を書いてみます。 使ったサービスは ACM ... Amazon の無料 SSL証明書 Route53 ... DNS EC2 ... オリジンサーバ ELB ... ALBを利用 S3 ... ログ置き場 CloudFront ... CDN CloudFront Functions ... IP制限, Basic認証 AWS WAF ... アクセス制限 あたりを使って実装していきます。 目次 目次 1. CloudFrontとは? 2. CloudFront用語 オリジンサーバ エッジサーバ ディストリビューション オリジンドメイン 3. CloudFrontの料金 CloudFront 無料枠 CloudFront オンデマンド料金 4. CloudFrontを使う準備 5. CloudFrontの設定方法 6. CloudFrontでWordPressを配信する デフォルトのビヘイビアの編集 7. CloudFrontでWordPressを配信するときの注意点 おまけ アクセス制限 8. まとめ 1. CloudFrontとは? CDN の一つがCloudFrontです。 CDN とは、Contents Delivery Network の略で、コンテンツを配信するネットワークという意味合いです。 CloudFrontは AWS が提供する CDN で世界中にエッジサーバが存在しているため、どこからアクセスしても爆速でレスポンスが返ってきます。 2. CloudFront用語 CloudFrontを語るには、以下の用語はおさえておきたいところです。 CDN の基本用語とも被るところはありますので「知ってる!」という方はすっ飛ばしてください。 オリジンサーバ エッジサーバ ディストリビューション オリジン ドメイン キャッシュビヘイビア では順番に説明していきます。 オリジンサーバ CloudFrontが配信するコンテンツが置いているサーバのことです。( AWS でいうとEC2とかS3とか) CloudFrontのエッジサーバにキャッシュがなかった場合、オリジンサーバまでリク エス トが届きます。 エッジサーバ 世界中に存在しているCloudFrontのキャッシュサーバたちのことです。 ブラウザでアクセスすると、まずエッジサーバにリク エス トが行くように DNS の設定を行います。   エッジサーバがキャッシュを持っていなかったときは、オリジンサーバにリク エス トが行きます。 逆にエッジサーバがキャッシュを持っていれば、そのままエッジサーバがキャッシュされたページをブラウザに返します。 ディストリビューション CloudFrontが配信するサイト…というか設定…のことを言います。 複数のサイトを1つの ディストリビューション で設定することも可能ですが、サイトごとにキャッシュの設定を変更したい場合などもあるので個人的には1 ディストリビューション につき、1サイトとしたほうが柔軟性は高いと思います。 本記事では1 ディストリビューション 、1サイト構成で説明していきます。 オリジン ドメイン ブラウザからアクセスさせたい ドメイン のことです。 例えば、 https://rakus.co.jp/ へのアクセスをエッジサーバ経由にしたい場合、CloudFrontのオリジン ドメイン 部分に rakus.co.jp を設定します。 3. CloudFrontの料金 CloudFront 無料枠 1TBのデータ転送(アウト) 1,000万件のHTTP, HTTPS のリク エス ト 200万件のCloudFront Functionsの呼び出し CloudFront オンデマンド料金 エッジサーバからインターネットへのデータ転送(アウト)の料金 (GB 単位) 10TBまで0.114(USD) 次の40TBまで0.098(USD) 次の100TBまで0.086(USD) オリジンサーバからエッジサーバへのデータ転送(アウト)の料金 (GB 単位) 0.060USD HTTPメソッドリク エス ト料金(1万件当たり) HTTP: 0.0090(USD) HTTPS : 0.0120(USD) CloudFront Functions (100万件当たり) 0.10(USD) 詳しくは 公式 をご覧ください。 4. CloudFrontを使う準備 ドメイン を用意 ( DNS 登録含む) ACM ( AWS が提供している無料の SSL証明書 ) ELB or S3 (コンテンツがおかれているオリジンサーバ) ※ ACM は 米国東部( バージニア 北部)(us-east-1)リージョン で発行しなければCloudFrontでは使えません。 ※オリジンサーバの構築場所に東京リージョンを使う場合、東京リージョンで ACM の発行も必要です。  (2か所で設定するのめんどくさいですが。) 5. CloudFrontの設定方法 さて、それではそろそろ実際にCloudFrontの始め方、設定方法を見ていきましょう。 まずは、CloudFront ディストリビューション 作成ボタンをクリックします。 続いて各項目を入れていきます。 オリジン CloudFrontにオリジンサーバを教えてあげる項目です。 オリジン ドメイン ELBかS3の バケット を指定(今回はELB) マッチビューアー アクセスできる プロトコル を選択 両方アクセスさせたいときはマッチビューワー オリジンパス 「/」を入れればOK 名前 基本的には何でもいいですが、サイト名とかわかりやすいのにするといいと思います デフォルトのキャッシュビヘイビア CloudFrontのキャッシュを持たせる設定を行う項目です。 初期設定ではCloudFront経由でアクセスした全リク エス トに対してキャッシュの設定されてしまいますが、後で URI 毎にキャッシュの設定が可能です。 オブジェクトを自動的に圧縮 Yesにしておくとよい。転送量が減って気持ち節約になります ビュー ワープロ トコルポリシー Redirect HTTP to HTTPS にしておくのが無難ですかね 許可されたHTTPメソッド サイトに合わせて設定してください 静的サイト…GET,HEAD 動的サイト…GET,HEAD,OPTIONS,PUT,POST,PATCH,DELETE 今回は WordPress なのでこっち キャッシュキーとオリジンリク エス ト 基本的に触らないくていい 設定 エッジサーバについての設定を行う項目です。 料金クラス すべてのエッジロケーションを使用する AWS WAF ウェブ ACL アクセス制限やWAFをいれたい場合はここで設定を追加 ※ もちろん AWS 側でルールを作る必要あり 代替 ドメイン アクセスさせたい ドメイン 名を記載(複数記載OK) CloudFrontを使う準備に記載した ドメイン を入力してもらえればOK 例) www.rakus.co.jp, rakus.co.jp など カスタム SSL証明書 ACM で取得した証明書をプルダウンから選択 標準ログ記録 必要な場合はオンにして、ログを保存するS3 バケット を設定 IPv6 対応していなければオフに 以上でCloudFrontの初期設定は完了です。 最期に「 ディストリビューション の作成」をクリックしましょう。 6. CloudFrontで WordPress を配信する さて、 ディストリビューション の作成が完了したので続いては WordPress 特有の設定を入れていきましょう。 オリジンサーバに WordPress をインストール ELBの設定 今回の投稿では上記については割愛させてもらいます。 <m(__)m> 「 WordPress インストール」というような記事でググって入れてください <m(__)m> 最低限、CloudFrontで WordPress を配信するだけなのであればここまでの設定で配信可能です。(多分。) が、このままでは WordPress の管理画面にアクセスできず、 記事の更新 WordPress のアップデート プラグイン のインストール などなどが管理画面上から行えないため、辛いです。 そのため、 WordPress 管理画面へのアクセスができるようにキャッシュをコン トロール しなければいけません。 その設定を入れていきます。 作成した ディストリビューション を編集するために設定画面に遷移します。 ビヘイビア > ビヘイビアを作成 をクリック パスパターン パスパターンを指定して、指定したパスにアクセスが来たときのキャッシュの挙動を設定 キャッシュしてはいけないパスパターン /wp-admin/* ( WordPress をインストールしたパスに合わせてください。) *. php * preview * オリジンとオリジングループ ディストリビューション 名が出てくるので作成した ディストリビューション の名前に合わせてください ビューワー デフォルトのキャッシュビヘイビアで設定した物と同じ設定を入れる キャッシュキーとオリジンリク エス ト Legacy chache settings ヘッダー:すべて (キャッシュしないように設定) 上記の設定でキャッシュしてはいけないパスパターンを作成してください。 - キャッシュしてはいけないパスパターン - /wp-admin/* (WordPressをインストールしたパスに合わせてください。) - *.php - \*preview\* デフォルトのビヘイビアの編集 デフォルトのビヘイビアを編集する前にキャッシュポリシー、オリジンリク エス トポリシーを作成します。 デフォルトのビヘイビアに作成したキャッシュポリシー、オリジンリク エス トポリシーをアタッチするイメージです。 ■ キャッシュポリシー まずはキャッシュポリシーを作成します。 CloudFrontトップ画面 > ポリシー > キャッシュ > キャッシュポリシーを作成 名前 わかりやすい名前なら何でも。 別の ディストリビューション にもアタッチできるので汎用的なキャッシュポリシー名にするのも良き 説明 適当に説明文を入れる キャッシュキーの設定 ヘッダー Host, CloudFront-Forwarded-Proto を入れてください Host:ALBが振り分けられなくなります CloudFront-Forwarded-Proto:EC2が80番しか開けていない場合これがないと表示崩れます 設定できたら作成をクリックして、キャッシュポリシーを作成します。 ■ オリジンリク エス トポリシー 続いて、オリジンリク エス トポリシーの作成をやっていきます。 CloudFrontトップ画面 > ポリシー > オリジンリク エス ト > オリジンリク エス トポリシーを作成 名前 キャッシュポリシーと一緒 説明 キャッシュポリシーと一緒 オリジンリク エス トの設定 ヘッダー キャッシュポリシーと一緒 クエリ文字列 * preview * cookie comment_author_* wordpress _test_ cookie wordpress _logged_in_* wp-settings-* 設定できたら作成をクリックして、オリジンリク エス トポリシーを作成します。 ここまでできたら、デフォルトのビヘイビアを編集していきます。 ■ デフォルトのビヘイビア さて、キャッシュポリシーとオリジンリク エス トポリシーが出来たので、デフォルトのビヘイビアの編集をしていきます。 CloudFrontトップ画面 > ディストリビューション > 作成した ディストリビューション > ビヘイビア > デフォルト > 編集 キャッシュキーとオリジンリク エス ト キャッシュポリシー さっき作ったキャッシュポリシーを選択 オリジンリク エス トポリシー さっき作ったオリジンリク エス トポリシーを選択 編集箇所はここだけです。 変更を保存しましょう。 さて設定もできたので、CloudFront経由でアクセスしてみましょう。 できた!! 7. CloudFrontで WordPress を配信するときの注意点 CloudFrontで WordPress を配信することができるようになりました。 私が初めてこの作業をやったときにハマったポイントを、いくつか記載しておきます。 LB配下に WordPress をインストールしたときはwp-config. php に とある記述 が必要 管理画面にアクセスできなかった… キャッシュの設定はご注意を 記事を更新するたびにCloudFrontのキャッシュをクリアしないといけない Wodpressに プラグイン があるのでそいつを使うと便利 テーマはなどの更新は多分検知されない… というところでしょうか。 おまけ アクセス制限 CloudFrontでアクセス制限を掛けたいときってありますよね?(例えば検証機とか。) 接続元がCloudFrontの IPアドレス になっていた、ELBのIPになっていたりとサーバ側で制限をかけるのが結構めんどくさいです。 そんな時に役立つのが AWS WAF, CloudFront Functions です! IP制限したいな~と思ったら下記を試してみてください<m(__)m> AWS WAF CloudFront Functions また、CloudFront以外からのアクセスを遮断したい!みたいなこともあるかと思います。 悪い人がhostsファイルなどでサーバに直接アクセスできるようにしてくるかもしれません。 そんな時は一つの方法として、CloudFrontが付与したカスタムヘッダーをLBが判定する方法が手っ取り早くて楽だと思います。 しかし、最近だともう少し楽にできる方法もあるみたいです。 お時間あれば調べてみてください。 8. まとめ 長い記事を呼んでいただき、ありがとうございました。 CloudFrontを使うと運用がめんどくさくなることもありますが、サイト自体が軽量化でき、 SEO 対策にもなります。 以前、 WordPress で作った弊社オンデマンドサイトはアクセス集中が起きると必ず落ちていましたが、CloudFront経由で配信するようにしてからは(多分)1度も落ちていません。 アクセス集中で困っている! すぐ高負荷になって困っている! という方は、一度CloudFrontや他の CDN の構成を検討してみてもいいかもしれないです。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
技術広報の yayawowo です。 いつも ラク スのエンジニアブログをお読みいただき、ありがとうございます! 今年度3回目となる ラク スMeetupは、 『 開発速度向上のためのリファクタリング術 〜負債をきっちり返済しよう〜 』 でした! テーマは『技術的負債・生産性向上』です。 ローンチ5年〜20年を迎える3プロダクトを支える、弊社のバックエンドエンジニアの3名が登壇しました! なお、本イベントは以下のような方にオススメとなっております。 ◆ こんな方にオススメ! ・ ラク スのプロダクト、組織に興味がある方 ・長期プロダクトの リファクタリング を検討している方 ・UI刷新、オフショア開発に興味がある方 ・ SaaS 開発に携わるエンジニアの話が聞いてみたい方 発表の紹介 サポートチャットサービスをローンチしてから5年間で発生した負債と対策 レガシーなシステムのリファクタリングに取り組んで学んだこと 20年以上のレガシーシステムで始めるリファクタリングの半歩 秋開催!おすすめ技術イベント ラクスのエンジニア/デザイナーと話をしてみたい方へ 終わりに 発表の紹介 それではここから各発表内容と資料を共有させていただきます! イベントの詳細は以下をご確認ください。 rakus.connpass.com サポートチャットサービスをローンチしてから5年間で発生した負債と対策 登壇:酒井 幸教 [所属:チャットディーラー開発課/担当プロダクト: ChatDealer ] speakerdeck.com 1本目は、チャットディーラー開発課の酒井さんによる発表です。 システム開発 を行う中で、様々な条件によって技術的負債は生み出されてしまいます。 サポートチャットボットを提供するサービス『ChatDealer』はローンチされてから5年目であり、 ラク スでは新しめのサービスです。 しかし、開発を進める中で様々な技術的負債が生じております。 本発表では、以下ポイントを中心にお話させていただきました。 『ChatDealer』で技術的負債が生じた経緯 技術的負債の解消に向けた対策 レガシーなシステムの リファクタリング に取り組んで学んだこと 登壇:ファム ブイテー ニャン [所属:配配メール開発課/担当プロダクト: 配配メール ] speakerdeck.com 続いて、配配メール開発課にてブリッジSEを担当しているニャンさんの発表です。 レガシーなシステムでは、古いコードの書き方、保守性・可読性が悪い書き方などがよくあると思います。 リファクタリング はこのようなシステムで生産性を向上するための一つの手段です。 私は約15年稼働しているメール配信システムのブリッジエンジニアとして、オフショアチームと一緒に リファクタリング を実施してきました。 リファクタリング の経験で良かったことと苦労したこと、そこから学んだ リファクタリング する時に注意することをご紹介しました。 なぜ リファクタリング を実施しないといけないのか リファクタリング で良かったことと苦労したこと リファクタリング する時に注意すること 20年以上の レガシーシステム で始める リファクタリング の半歩 登壇:四方 大輔 [所属:メールディーラー開発課/担当プロダクト: MailDealer ] speakerdeck.com ラストは、メールディーラー開発課の四方さんが発表しました! 20年以上サービスが続くメールディーラー。 そんな社内最長老であるサービスに突如言い渡されたUI刷新プロジェクト。 流行りのUIにしたい?新しい フレームワーク を使う!? フロンドエンドとバックエンドは密結合!!? こんなシステムどうやってUI刷新するの??本当に安全にリリースできるの??? 私たちがメールディーラーUI刷新プロジェクトを通して得た、 " レガシーシステム でもできる"安全な リファクタリング の始め方についてお話しました。 秋開催!おすすめ技術イベント ラク スでは、定期的にエンジニア/デザイナー向けの技術イベントを開催しております。 その中から9月~10月に開催する、技術イベントをご案内いたします。 ◆ LT会 9/21(水)開催: エンジニアの勉強法ハックLT- vol.10 9/22(木)開催: エンジニアのためのDX 10/12(水)開催: コードレビュー LT会 - vol.3 10/19(水)開催: プロジェクトマネジメント Tips LT会 vol.5 10/20(木)開催: QA Tips LT会 - vol.2 10/26(水)開催: UI/UXデザイナーLT会 - vol.9 10/27(木)開催: Reactをもっと語りたい! ◆ TechCafe 9/27(火)開催: PHPerのための「PHPカンファレンス2022」を語り合うPHP TechCafe 9/28(水)開催: 「k8s」を語るCloud Native TechCafe #2(ゲスト:bells17様) ◆ Meetup 10/5(水)開催: アーキテクチャカイゼンで課題解決に挑む、エンジニア達 1つでもご興味があるものがございましたら、お気軽にご参加ください! 採用イベントも開催中!こちらも合わせてご確認ください。 ・9/26(月)開催: SREチームの仕事紹介/カジュアル説明会 ラク スのエンジニア/デザイナーと話をしてみたい方へ 当社では、一緒に働くエンジニア/デザイナーを積極的に募集しております! 現在募集している職種は、以下サイトよりご確認ください。 career-recruit.rakus.co.jp 「まだ応募する段階では…」 という方は、是非 カジュアル面談 もご検討ください! 【こんな方におすすめ】 ポジションが経験にマッチするか確認したい 働き方/環境・体制/事業・プロダクト/文化/制度を詳しく知りたい 応募前に選考の概要を聞きたい(人物像、基準など) エンジニア・デザイナーの人となりを知りたい 以下申込フォームとなります。 rakus.hubspotpagebuilder.com 「イベントで登壇していた●●さんと話してみたい・・・」 などご要望がありましたらその旨をご記入の上、お申込みください! お気軽にどうぞ 😊 終わりに 『開発速度向上のための リファクタリング 術 〜負債をきっちり返済しよう〜』はいかがでしたでしょうか? ローンチ5年〜20年を迎える3プロダクトを支える、最前線エンジニアによる技術取り組みを発表させていただきました。 本発表が SaaS 開発に携わるエンジニア/デザイナーの皆様にとって、一つでもご参考になれば幸いです。 最後までお読みいただきありがとうございました! エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
こんにちは、インフラエンジニアのfro-rivです。 業務でよく使う機会がある(私はよくある)diffコマンドですが、調べてみると知らなかったオプションがたくさん… ※ diff ${file1} ${file2} の通り、簡単に 使えるが故に 今までちゃんと調べたことはありませんでした。 今回は、そんなdiffコマンドの表示オプションを中心に紹介できればと思いますので、よろしければご覧ください。 diffコマンドとは よく使うオプション diffコマンドのオプションで変わる表示形式 -uオプション:unified形式 -cオプション:context形式 -yオプション:side by side形式 --suppress-common-lines(共通行非表示)と組み合わせる -W(表示幅指定)と組み合わせる --colorオプション:色表示(番外編) 最後に 参考文献   diffコマンドとは diffコマンドは、 2つのファイルを比較して違い(差分)を出力するコマンド です。 またリダイレクトを使えば、コマンド実行結果などの文字列比較も行うことができます。 以下、例 ###ファイル比較(基本) $ diff file1.txt file2.txt 1c1 < test --- > tests ###リダイレクトしたコマンド実行結果(文字列)を比較 $ diff < ( echo ' test ' ) < ( echo ' tests ' ) 1c1 < test --- > tests よく使うオプション diffコマンドで よく使うオプション のご紹介です。 私は今回調べるまで、patchファイルを作るときに -u を使ったりするくらいでしたが、便利なオプションがたくさんありました。 オプション 説明 -c context形式で差分を表示 ! (変更点)や + (追加), - (削除)で表示される -u unified形式で差分を表示 変更点は + , - で表示される -y --side-by-side 横並びで差分を表示 | (変更点)や < (削除), > (追加)で表示される -q --brief 差分があれば、差分がある旨メッセージを出力 ※差分は出ない ※差分がなければ出力もなし -s 差分があれば、差分を出力 無ければ、差分がない旨メッセージを出力 -b 空白の差分は無視 -i --ignore-case 大文字小文字の区別をしない --suppress-common-lines 共通行を表示しない ※-yオプションと併用で効果あり -W --width=${NUM} 表示幅を指定する ※-yオプションと併用で効果あり (デフォルト: 130カラム) --color 色付きで差分表示する ※diffutils3.4以上で有効 diffコマンドのオプションで変わる表示形式 よく使うdiffコマンドのオプションの違いでどのように表示形式が変わるのか、いくつか実際にご紹介したいと思います。 比較するファイルは下のものを使用します。 test1.txt ファイルに手を加え test2.txt を作成しましたので、 それぞれ説明の際は、 test1.txt を 変更前 、 test2.txt を 変更後 とさせていただきます。 # cat test1.txt あいうえお かきくけこ さしすせそ たちつてと なにぬねの はひふへほ まみむめも やゆよ らりるれろ わをん アイウエオ # cat test2.txt あいうゑお かきくケこ さしすせそ たちつてと ららららら なにぬねの はひふへほ まみむめも やゆよよよ らりるれろ わをん ちなみに、オプションなしでdiffコマンドを使って比較するとこんな出力となります。 この文量なら何とかなりますが、差分がもっと増えると、正直何が何だか分かりにくい… # diff test1.txt test2.txt 1 ,2c1, 2 < あいうえお < かきくけこ --- > あいうゑお > かきくケこ 4a5 > ららららら 8c9 < やゆよ --- > やゆよよよ 11d11 < アイウエオ # -uオプション:unified形式 まずは、unified形式です。 --- の部分は変更前のファイルを、 +++ は変更後のファイルを表しており、 変更後に存在しない行は - 変更後にのみ存在する行は + が行頭についてます。 こちらのオプションは見やすさで選ぶというよりも、patchを当てたりするため、使うことが多い気がします。 # diff -u test1.txt test2.txt --- test1.txt 2022-08-22 18:23:54. 717925300 + 0900 +++ test2.txt 2022-08-23 09:18:48. 147925300 + 0900 @@ -1 , 11 + 1 , 11 @@ -あいうえお -かきくけこ +あいうゑお +かきくケこ さしすせそ たちつてと +ららららら なにぬねの はひふへほ まみむめも -やゆよ +やゆよよよ らりるれろ わをん -アイウエオ # -cオプション:context形式 次に、context形式です。 *** の部分は変更前のファイルを、 --- は変更後のファイルを表しており、 変更のあった行は ! 変更後に存在しない行は - 変更後にのみ存在する行は + 行頭についています。 こちらのオプションも、一目で見てわかるという感じではありませんね。 # diff -c test1.txt test2.txt *** test1.txt 2022-08-22 18:23:54. 717925300 + 0900 --- test2.txt 2022-08-23 09:18:48. 147925300 + 0900 *************** *** 1 , 11 **** ! あいうえお ! かきくけこ さしすせそ たちつてと なにぬねの はひふへほ まみむめも ! やゆよ らりるれろ わをん - アイウエオ --- 1 , 11 ---- ! あいうゑお ! かきくケこ さしすせそ たちつてと + ららららら なにぬねの はひふへほ まみむめも ! やゆよよよ らりるれろ わをん # -yオプション:side by side形式 次に、side by side(横並び)形式です。 非常に見やすい(直感的にわかりやすい)表示となっており、すべての比較で使いやすいとまでは言いませんが 私が一番頻繁に使用するdiffコマンドのオプションになります。(オススメ!) 左側に変更前・右側に変更後のファイルが表示されており、変更行があれば真ん中に記号がつきます。 変更のあった行は | 変更後に存在しない行は < 変更後にのみ存在する行は > が表示されます。 以下の様に、直感的にわかりやすい表示となっております。 (ご覧の端末の幅によってはコマンド結果がきれいに表示できていないかもしれませんが、ご了承ください) # diff -y test1.txt test2.txt あいうえお | あいうゑお かきくけこ | かきくケこ さしすせそ さしすせそ たちつてと たちつてと > ららららら なにぬねの なにぬねの はひふへほ はひふへほ まみむめも まみむめも やゆよ | やゆよよよ らりるれろ らりるれろ わをん わをん アイウエオ < # -y オプションを知らなかった時は、 diffコマンドが見づらいのでリモートサーバからわざわざローカルPCに比較ファイル持ってきて WinMerge を 使っていました。 -y オプションにはさらに見やすくなるオプションもありますので、以下にてご紹介させていただきます。 --suppress-common-lines(共通行非表示)と組み合わせる diff -y コマンドに --suppress-common-lines オプションを加えると、差異のある行のみを表示してくれます。 通常共通行も表示され、それはそれで便利なこともあるのですが、 --suppress-common-lines オプションを使うことで 簡潔に表示させることができます。 # diff -y --suppress-common-lines test1.txt test2.txt あいうえお | あいうゑお かきくけこ | かきくケこ > ららららら やゆよ | やゆよよよ アイウエオ < # -W(表示幅指定)と組み合わせる 例で使っているような各行の文字数が少ない場合、または多い場合 diff -y だけでは少し見づらいこともあります。 そんな時には -W ${カラム数} (デフォルト:130カラム)オプションをつけることで表示幅を変更することもできます。 今回比較に使用しているファイルは各行の文字数が少ないので、30カラムを指定してみます。 # diff -y -W 30 test1.txt test2.txt あいうえお | あいうゑお かきくけこ | かきくケこ さしすせそ さしすせそ たちつてと たちつてと > ららららら なにぬねの なにぬねの はひふへほ はひふへほ まみむめも まみむめも やゆよ | やゆよよよ らりるれろ らりるれろ わをん わをん アイウエオ < # これでかなり見やすくなりました。 さらに、1つ前に紹介した --suppress-common-lines を組み合わせると、差異のある行のみをさらに見やすく表示できます。 # diff -y -W 30 --suppress-common-lines test1.txt test2.txt あいうえお | あいうゑお かきくけこ | かきくケこ > ららららら やゆよ | やゆよよよ アイウエオ < # ちなみに、1行当たりの文字数が多いと、途中で切れてしまうので -W 170 など広めに設定すれば見やすくなります。 (ご覧の端末の幅によってはコマンド結果がきれいに表示できていないかもしれませんが、ご了承ください) ###デフォルトの130だと最後まで見れない # diff -y file1.txt file2.txt 1234567891011121314151617181920212222324252627282930313233343 | 1234567891011121314151617181920212222324252627282930313233343 ###幅を170にするとファイルの端の文字まで確認できる # diff -y -W 170 file1.txt file2.txt 123456789101112131415161718192021222232425262728293031323334353637383940 | 123456789101112131415161718192021222232425262728293031323334353637383950 # --colorオプション:色表示(番外編) こちらはdiffコマンドのオプション番外編となりますが、 diffutils のバージョン3.4以降で使用できる色表示オプションになります。 CentOS7の公式 リポジトリ で提供されている diffutils は3.3系が最新でしたので使えませんが、CentOS8系からは使用できるかと思います。 こんな感じで、diffを色表示できるので視覚的に見やすいです。 ※epel リポジトリ にて、 colordiff というパッケージも配布されているようですので、 --color オプションが使えない方は、 インストールしてみてください。 diff --color実行結果 最後に 今回は、diffコマンドの表示形式を見やすく、ファイル比較を楽にするためのオプションについて紹介しました。 記事内にも記載しておりますが、diffコマンドについて詳しく調べるまでは、業務でリモートサーバ上のファイルを比較するとなると毎回ローカルPC上に持ってきて WinMerge を使っておりました。 特に -y のオプションは WinMerge に似た出力となり直感的に変更点がわかりやすいということから、今や -y オプションに頼りきりです。笑 diffコマンドを使いこなして、 “楽” にファイル比較をしましょう。 というわけで、diffコマンドのオプション紹介でした。 参考文献 DIFF GNU diff utilities - News: diffutils-3.4 released [stable]     エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 https://rakus.hubspotpagebuilder.com/visit_engineer/ rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
特集「 Xdebug の活用方法」を語る 弊社で毎月開催し、 PHP エンジニアの間で好評いただいている PHP TechCafe。 2022年2月のイベントでは 「 Xdebug の活用方法」 について語り合いました。 弊社のメンバーが事前にまとめてきた Xdebug の基礎知識や使い方の説明資料にしたがって、他の参加者に意見を頂いて語り合いながら Xdebug の活用方法を学びました。 今回はその内容についてレポートします! rakus.connpass.com 特集「Xdebugの活用方法」を語る デバッグツールについて Xdebugとは 導入方法 公式のインストール手順 Xdebugの便利な機能 Step Debugging ステップデバッグとは デバッグ方法 (PhpStorm) 1. 受信デバッグ接続のリッスンを有効にする 2. ブレークポイントをセット 3. デバッグセッションの開始 ステップデバッグでできること デバッグセッション再開 ステップオーバ (F8) ステップイン (F7) ステップアウト (F8) 強制ステップイン 停止している処理での調査 フレーム調査 変数の調査 / 更新 式の評価 その他テクニック 停止している行を表示 ウォッチリストに変数を追加 ブレークポイントのミュートモード その他の機能 1. エラーレポート 詳細 php.ini var_dump()の強化 2.スタックトレースの追加 3.トレーシング トレースとは 4. プロファイリング 機能の概要 使い方 5.Code Coverage Analysis 機能の概要 使い方 カバレッジ 編集後記 デバッグ ツールについて デバッグ ツールとはバグを除去するときに使用するツールです。 ※ デバッグ (debug) は de(除去) - bug(不具合)という意味です。 多くの デバッグ ツールは以下の基本性能を備えています。 ブレイクポイント 実行中のプログラムを任意の箇所で一時停止する ステップ実行 ソースコード を1ステップずつ実行する 変数の可視化・変更 実行中のプログラムの変数の値を確認したり変更する 関数・式の実行 デバッグ 中に任意の関数や式を実行する デバッグ ツールがないとバグ修正が大変になるケースとして、以下が挙げられました。 大量に デバッグ ログを仕込むことになる 処理を通すことが難しい部分を デバッグ する時 同時実行など再現が難しい場合 デバッグ 用に入れた処理が本番に残ってしまって大災害を引き起こす その他、var_dumpなどで手軽にコードの動きを見たい場合はそちらを活用するなど、 「ツールとコードの両者を柔軟に使えると良い」という意見もありました。 Xdebug とは PHP で デバッグ を行う上で便利な機能を提供する、 拡張機能 です。 PHP においては、 デバッグ ツールの デファクト ツールになっているものです。 多機能で、基本的な デバッグ ツールとしての機能だけでなく、様々な機能を持っています。 デバッグ の機能が使われることが多いですが、他にも様々な便利機能があり順に紹介されました。 導入方法 Xdebug は C言語 で実装されており、 コンパイル されたファイル .soファイル を組み込む( php .iniに読み込み設定を追記)ことで有効になります。 導入手順は公式のものを使用する方法と、Dockerを使用する方法の2つが紹介されました。 公式のインストール手順 Linux : 公式リポジトリ こちらの方法ではメリットとして最も手軽であることが挙げられましたが、デメリットとして最新バージョンが入らないこともあるようでした。 Xdebug の最新バージョンはv3系ですが、Ubuntu20.04ではv2系が入ってしまうため、注意が必要です。 PECL(ピクル) ※ PECL : PHP の 拡張機能 やライブラリなどを追加するためのパッケージ管理ツール php .iniへの設定も自動で行ってくれるため、 Mac ユーザーにとっては便利だという紹介がありました。 ソースをコンパイル こちらの方法が必要なケースとしては 特定のバージョンが必要 ネットワーク、セキュリティの関係上パッケージ管理ツールが使用できない といったことが挙げられました。 また、「手順が難しいわけではないが、コマンドを検索しソースから コンパイル される場合に、 実際に何が行われているかということを理解してから行う方がよい のではないか?」という意見もありました。 Dockerで使う 公式イメージの説明 Dockerfileの例 FROM php:8.1-cli RUN pecl install xdebug \ && docker-php-ext-enable xdebug docker-php-ext-enable を記述すると、コンテナ上の PHP で Xdebug が有効化されます。 自身のプロジェクトの状況や環境に合わせて、様々な方法が選択できる点が非常に良いと思いました! また、 デバッグ の際に デバッグ ツールを使用するかどうかのアンケートの結果、ツールを使用しない方が多数派だったようです。 その結果を受けて、 Xdebug やdumpを利用することのメリット/デメリットが解説されました。 Xdebug のデメリットとしては動作が重い点が挙げられ、 php .iniで設定を消すなどして軽量化を図ったという経験が語られていました。 dumpのデメリットとしては、消し忘れが事故につながる点が挙げられ、できるだけログに出力するようにしているという方法が語られました。 他にも 新卒で入ったときに先輩から 「ウェブブラウザの画面には出すな事故るから」 って言われましたね。 「何かAAAって出てきたんだけど」って。そんな報告聞きたくない!冷や汗すごいと思う。 「var_dumpで事足りるじゃん」って宗教になってしまいました。「いやそれはないから目を覚ませ」って言った記憶があります。 などの体験が語られていました。 最後に Xdebug を簡単に入れられない古いサービスとかだとやむなし Xdebug が使える人はどんどん使っていくほうが良い という結論に至りました。 Xdebug の便利な機能 Step Debugging Xdebug の機能について、PhpStormの画面を使って紹介されました。 ステップ デバッグ とは 任意の行で処理を止めながら行う、 デバッグ のことです。 デバッグ 方法 (PhpStorm) 1. 受信 デバッグ 接続のリッスンを有効にする 2. ブレークポイント をセット 3. デバッグ セッションの開始 対象のページをリロードすると、 ブレークポイント で処理が止まります。 ステップ デバッグ でできること デバッグ セッション再開 次の ブレークポイント へ進む 次に通った ブレークポイント にて再度処理が止まる ステップオーバ (F8) 次の行へ処理を進める 進める行のメソッドがある場合、メソッド内の処理はスキップされる メソッド内に ブレークポイント がある場合は、そこで止まる "強制ステップオーバ" を使うことで、スキップもできる ステップイン (F7) メソッド内の処理を調べたい時に利用 止まっている行にあるメソッド内の処理に入って先頭処理で止まる ステップアウト (F8) 調査中のメソッド内に問題がないことがわかった時に利用 現在のメソッドから抜けだして、呼び出し元の処理で止まる 強制ステップイン ステップインでは サードパーティ のライブラリなどのメソッドへ入ることができない 強制ステップインでは、これらのメソッド内の処理へ入ることができる このあたりの機能を見るだけでも、var_dumpで デバッグ するよりも色々なことができることが分かります。 ここで紹介された機能について、 「基本的にはこのステップアウトぐらいまでは割とどういう IDE でもありますかね。」 「強制ステップインはPhpStormにユニークな機能として実装されていますね。」 「正直強制ステップインはあまり使わずに何とかなっていたので、意図して使い分けたりとかはしてなかったですね。」 といった経験が語られました。 停止している処理での調査 よくコードを追っていると行を見失うことがありますが、「停止している行を表示」するアイコンを押すと止まっている行に移動してくれます。 それらの機能について紹介されました。 フレーム調査 どこから呼び出された処理かを確認できます。 変数の調査 / 更新 現在の変数に格納された値の確認 値の編集も可能 式の評価 選択した部分の式評価 アイコンから任意の式での評価結果確認も可能 こちらの機能については Xdebug で止めながら、途中に適当な評価式を書いて変数の中身を見る必要がなく、直接確認できるというメリットが紹介されました。 その他テクニック その他、いくつか紹介された機能を挙げておきます。 停止している行を表示 デバック時に停止している行を見失った時に使用 ウォッチリストに変数を追加 変数を監視リストとして登録可能 ブレークポイント のミュートモード ONにして以降の ブレークポイント で処理を止めなくなる Xdebug で最も使用される、ステップ デバッグ についての紹介は以上でした。 その他の機能 続いて、その他便利機能が5つ紹介されました。 まずはエラーレポートを向上させてくれる機能の紹介です。 こちらは大きく分けてvar_dumpの強化、 スタックトレース 追加の2つがあります。 1. エラーレポート 詳細 まずは、 php .iniの xdebug .modeをdevelopにする必要があります。 php .ini xdebug.mode=develop var_dump()の強化 var_dumpの出力を成形したり、装飾するためにHTMLエラーを有効にする必要があります。 html_errors=1 補足情報として、 php.ini の html_errors 設定が有効のときしかキレイにならないという注意点が挙げられました。 公式リファレンス こちらのサンプルとしては、arrayに色々な値を入れてvar_dumpで出力しています。 var_dump()の強化 サンプルコード <?php $ sampleArray = [ 1 , // int 0.1 , // float true , // bool "string" , // string [ "nest1" , [ "nest2" , [ "nest3" ]]] // array ] ; var_dump ( $ sampleArray ) ; こちらの出力結果をブラウザ上で表示すると、以下の結果になります。 developモードがOFFのとき developモードがONのとき この結果を受けて、developモードをONにしたときのメリットとして以下の点が挙げられました。 改行などを成形、intが緑でFloatがオレンジといったように色がつき、見やすくすっきりする ネストしている配列に、3つ目以降が省略されて表示される なお、ネストについては xdebug.var_display_max_depth を設定することで表示する階層を制御できます。 その他、 コマンドライン 上でも色を付ける方法が紹介されました。 こちらは xdebug.cli_color を設定することで表示される、var_dump()の結果に色を付けることができます。 参加者からも「var_dumpはプレタグで図った記憶がありますね」というコメントが挙がりました。 これをきっかけに 「この Xdebug できれいになっているのも、 HTMLのプレタグを付けてくれている っていうのがありますね。HTML化して共有してくれていると。」 「 Xdebug 入れずにvar_dumpしたらページのソースを見ると改行されているのが分かるって感じになりますね。ブラウザ上だとbrとかあるけど……」 「それでプレタグで囲ったらってことですね。」 「printlnなんかも使えますね。その辺り使ってわかりやすくできます。」 という話題で盛り上がりました。 2. スタックトレース の追加 エラーが起こった際、developモードをONにすると綺麗に出力してくれます。 developモードがOFFのとき developモードがONのとき ここでは注意点として 「 Xdebug ありでvar_dumpに吐き出すと、HTMLありで見にくくなる」 「var_dumpの結果をログに吐き出すときは developモードをoffにしたほうが良い 」 ということも紹介されました。 3.トレーシング トレースとは 関数がどういう経路で出力されているかを確認したり、関数の戻り値を確認することで、システムの全体像を把握することです。 Xdebug を使用することで関数呼び出しの履歴を出力できるため、以下のメリットが挙げられました。 関数がどのような経路で呼ばれているか、全体像を把握できる 引数、戻り値も確認できる また、 xdebug .mode=traceに設定するとトレーシングがオンになると紹介がありました。 php .ini(設定例) xdebug.mode=trace xdebug.trace_format=0 xdebug.output_dir=/tmp/tracing xdebug.start_with_request=no 続いてサンプルコードを使用し、実際に出力を確認しました。 サンプルコード <?php class SampleClass { public function a () { $ this -> b () ; } private function b () { var_dump ( "tracing" ) ; } } $ sampleClass = new SampleClass () ; xdebug_start_trace () ; $ sampleClass -> a () ; xdebug_stop_trace () ; $ sampleClass -> a () ; 実行結果 trace.1373756769.xtというファイルが出力されました。 Time列が実行時間、Mem列が使用しているメモリです。 Function列が呼び出している関数と場所を表しています。 また、矢印(->)でネストの深さも表しています。 この結果について参加者から 「traceの実行時間まで出るのすごいですね。」 というコメントがあり、それをきっかけに 「 ボトルネック を調べられるの便利 ですよね。DBのI/Oのアクセスとかなら SQL いじるとかありますし。」 「遅そうなところにこういうのを仕込んで、 PHP の処理は遅くないけど内部実行のDBアクセスに時間かかってるなあって 原因の切り分けがしやすそう ですね。」 というメリットが会話で挙げられました。 また、以下の補足情報も紹介されました。 xdebug.collect_assignments 関数に渡された引数の値を出力できる xdebug.collect_return 関数の戻り値の値を出力できる xdebug.trace_format で出力フォーマットを選択できる 1(コンピューター可読形式):実行結果 これについては、 「公式が分析用の スクリプト を準備してくれている」 「 GitHub の中に載っているんですがこの スクリプト に食わせて実行すると結構分析してくれます。 自分で分析用のプログラムとか組んでアレンジ することも出来るかもしれません。」 「人間には読めない形で出るのかと思ってました。関数ごとの呼び出しされた回数とかが出てきましたね。」 「一回データとして取り込んでしまえばこっちのものですからね。」 といった便利な活用方法が紹介されていました。 2(HTML):実行結果 この結果については、「人にやさしい」という意見が出ていました。 その他にも設定が多数あり、「結構いろいろできるんだな」という Xdebug の多機能さに感心する声もありました。 4. プロファイリング 機能の概要 処理の監視や記録を行う機能です。 処理に時間がかかっている箇所や、リソース消費の激しい箇所を特定することができます。 使い方 こちらもiniファイルに設定が必要です。 php .ini 設定 profile の設定を有効化 xdebug.mode=profile profile の出力先 xdebug.output_dir=/tmp/profiling これらを設定し PHP のプログラム実行すると、 xdebug.output_dir で指定した ディレクト リにファイルが出力されます。 出力されたファイルは人間には分かりにくいので実行結果を可視化するツールが公式で紹介されており、 Webgrind が個人的に使いやすいと紹介がありました。 この機能の活用シーンとしては パフォーマンスが悪い処理の ボトルネック 特定 意図しない箇所で例外処理されてしまって原因特定が困難な時 「実行したけれどどこで落ちたかわからない」ときにこれを実行すれば「ここで止まったな」というのがプロファイリングの結果からわかる といった紹介がありました。 また、参加者から 「PhpStormで開くと定義した場所にそのままコードジャンプ出来るので楽しいです」 というコメントがあり、これについて 処理が重なっているところを押したら、該当のコードへジャンプ出来るということです。 便利ですね! さすがPhpStorm! など、PhpStormへのポジティブな声が挙がりました。 他にも注意事項として、 現状の php .ini 設定の場合は、すべてのリク エス トが profiling されてしまう 処理が重い スクリプト を気にせず実行しまくっていると、プロファイルの実行結果だけでディスク容量をかなり食ってしまうことになる string xdebug.start_with_request を trigger に設定することで profiling を開始したいタイミングを指定できるため、不用意に実行されないようにしたほうが良いと思う といった点が挙げられました。 5.Code Coverage Analysis 機能の概要 処理を通過した箇所を記録することができます。 単体テスト などで、そのプログラムがどの程度テストできているかを把握できます。 使い方 基本的には PHPUnit と組み合わせるのが一般的です。 PHPUnit のコードカバレッジ も内部で Xdebug のコード カバレッジ を利用しています。 php .ini の設定はおそらく不要です ソースコード 上で カバレッジ を取得したい箇所を xdebug_start_code_coverage() と xdebug_stop_code_coverage() で挟むだけ xdebug_get_code_coverage() を実行することで上記で挟んだ箇所の カバレッジ を取得できます。 ここでは公式のサンプルコードを用いて話題が進みました。 Xdebug 公式サイト functionAとBが存在し、Bに6と10を与えて結果をもらってくる PHP ファイルがあるとします。 ここにstart_code_coverageを入れてget_code_coverageを実行し、var_dumpに出力させると実行結果が出てきます。 <サンプル > <?php xdebug_start_code_coverage ( XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE ) ; function a ( $ a ) { return ; echo $ a * 2.5 ; } function b ( $ count ) { if ( $ count > 25 ) { echo "too much \n " ; } for ( $ i = 0 ; $ i < $ count ; $ i ++ ) { a ( $ i + 0.17 ) ; } } b ( 6 ) ; b ( 10 ) ; var_dump ( xdebug_get_code_coverage ()) ; <実行結果> array '/home/httpd/html/test/xdebug/docs/xdebug_get_code_coverage.php' => array (size=11) 5 => int 1 6 => int -2 7 => int -2 10 => int 1 11 => int -1 13 => int 1 14 => int 1 16 => int 1 18 => int 1 19 => int 1 21 => int 1 実行結果がキーバリューの形で出力されます。 キー 対象ファイルの行数 値 : カバレッジ 取得結果 1: 実行した -1: 実行していない -2: デッドコードになっている まず 5 => int 1 に着目します。 サンプルコードの5行目 return; はreturnが実行できたので「1」となっています。 6 => int -2 は直前の5行目でreturnしており、その後の処理が絶対に実行されないので「-2」となっています。 11行目 if ($count > 25) は$countが25以上の時に実行されるコードですが、 サンプルコードは6,10しか渡しておらず条件を満たさないため実行されません。 そのため「-1」となっています。 カバレッジ 以前 ラク スエンジニアブログにて、テストコードの書き方をご紹介致しました。 tech-blog.rakus.co.jp その際に使用したコードの カバレッジ を見てみましょう。 DiceClassに対して作られたテストコードがどの程度カバーできているかを表しています。 結果は全て100%となっています。 テストケースとしての精度が高く、 カバレッジ としては問題無いですね。 このように、オールグリーン(100%)になっているかどうかをCode Coverageで確認することができます。 これによるメリットとして、 単体テスト のテストコードがどの程度書けているかを確認できるのはもちろん、「デッドコード」になっている箇所を 早期に見つけることができる 。 中々分岐に入らないケースですね。実際にリリースすると 「全然入っていない分岐があるけど、論理的にデッドコードじゃない?」 みたいなものがわからなかったりします。 そういったところも比較的実行し続ければある程度判断できるんじゃないかなと思います。 現実的じゃないですが本番環境やそれ相当のステージ環境に カバレッジ 処理を組み込んでぐるぐる回すことで「ずっと入っていない」ものを判断できると思います。 カバレッジ で一番知りたいのは PHPUnit がちゃんと通っているかですよね。網羅しているかどうかが一番重要になるパターンだと思うので。 Xdebug が提供しているっていうのが面白い ですね。燃える話です など、 Xdebug の機能の豊富さに改めて関心する声が多数挙がりました。 編集後記 以上、 Xdebug の概要と大まかな機能について取り上げました。 ラク スでも今まで取り上げることが無かった話題でしたので、主催者/参加者ともに盛り上がりを見せていました! 今後も Xdebug の活用方法や、新ニュースに着目していきたいと思います! 「 PHP TechCafe」では今後も PHP に関する様々なテーマのイベントを企画していきます。 皆さまのご参加をお待ちしております。 connpass.com エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
Gitを使用していると「あ!間違ったファイルをインデックスに上げてしまった!」ということ、ありますよね? (わたしはよくあります) 本投稿ではそんな git add の取り消し方法 についてまとめさせていただきます。 Gitを使い始めたばかりの方から、Gitコマンドについて学び直したいという方まで、開発の際に参考にしていただければ幸いです。 弊社テックブログの関連記事として、Gitの入門記事が以下にもございますのでよろしければ合わせてご一読ください。 【超入門】初心者のためのGitとGitHubの使い方 【Git入門】git stashで作業を便利に退避する 【Git入門】git commitを取り消したい、元に戻す方法まとめ 【Git入門】git cloneで既存リポジトリをクローンしよう! 【Git入門】git pullって?fetchとmergeとの使い分けをご紹介 目次 目次 git addとは? git addを取り消したい! git init直後のgit addの取り消し 前回のコミット後のgit addの取り消し git restoreを使用する方法 git resetを使用する方法 まとめ git add とは? まずはコマンド自体のおさらいです。 git add とは、 作業中の ディレクト リで行った修正をインデックスに追加するコマンド のことです。 (作業中 ディレクト リは「ワークツリー」とも呼ばれます) インデックスに追加することで、変更を加えたファイルをコミット対象とすることができます。 git add を取り消したい! 続いて、さっそく本題の git add の取り消し方法についてです。 git add を取り消す際は、「 git init 直後(コミットの無い状態)」と「コミットを打った以降」でコマンドが異なるので、それぞれの方法をご紹介します。 git init 直後の git add の取り消し Gitでバージョン管理をする手始めとして、まずは git init コマンドで対象 リポジトリ をGit管理下に置くための初期化を行います。 下記に、 git init sample.txt ファイルを作成(サンプル用の空ファイル) sample.txt をインデックスに追加 の流れを記載します。 $ git init Initialized empty Git repository in [初期化リポジトリのパス]/.git/ $ touch sample.txt $ git status On branch main No commits yet Untracked files: (use "git add <file>..." to include in what will be committed) sample.txt $ git add sample.txt $ git status On branch main No commits yet Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: sample.txt コミットの無い状態で、 sample.txt ファイルをインデックスに追加しました。 この状態から git add を取り消すには、 git rm コマンドを使用します。 $ git rm --cached [ファイル名] git rm コマンドはGit管理下にあるファイルを削除するためのコマンドです。 --cached オプションを使用することで、指定したファイルをインデックスから削除することができます。 (上述の git status 実行後にも (use "git rm --cached <file>..." to unstage) と記載されていますね) この --cached オプションを使用せずに git rm を実行してしまうと、ファイル自体が削除されてしまうので気をつけてください。 下記に実行例を記します。 $ git rm --cached sample.txt rm 'sample.txt' $ git status On branch main No commits yet Untracked files: (use "git add <file>..." to include in what will be committed) sample.txt 無事にファイルをインデックスから削除することができました。 -r オプションを使用することで、 ディレクト リを削除対象にすることもできます。 $ git rm --cached -r [ディレクトリ] また、インデックスに追加した全ての修正を取り消す場合は、ファイル名や ディレクト リ名無しでも実行可能です。 $ git rm --cached -r . 前回のコミット後の git add の取り消し 続いて、既にコミットが打たれている場合の取り消し方法をご紹介します。 (こちらの方が使用頻度としては高いと思われます) 現在のローカルブランチの状態を以下とします。 $ git log --oneline 6f099b1 (HEAD -> main) first commit この状態から以下手順でファイルをインデックスに追加します。 sample.txt ファイルを修正(既に該当ファイルに対してコミットが打たれている状態) 修正後の sample.txt をインデックスに追加 $ echo 'modify' > sample.txt $ git status On branch main Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: sample.txt no changes added to commit (use "git add" and/or "git commit -a") $ git add sample.txt $ git status On branch main Changes to be committed: (use "git restore --staged <file>..." to unstage) modified: sample.txt コミットが存在する状態で、修正を加えた sample.txt ファイルをインデックスに追加しました。 この状態から git add を取り消すには、 git restore 、もしくは git reset コマンドを使用します。 $ git restore --staged [ファイル名] $ git reset HEAD [ファイル名] git restore を使用する方法 git restore コマンドは特定の時点まで変更を元に戻すコマンドです。 --staged オプションを使用することで、指定したファイルをインデックスから削除することができます。(インデックスの復元) (上述の git status 実行後にも (use "git restore --staged <file>..." to unstage) と記載されています) この --staged オプションを使用せずに git restore を実行した場合、ワークツリー内の変更も失われてしまうので注意してください。 (インデックスにファイルがある場合は問題ありません) 下記に実行例を記します。 $ git restore --staged sample.txt $ git status On branch main Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: sample.txt 無事にインデックスから削除できました。 全ファイルを対象とする場合は下記のように実行してください。 $ git restore --staged . git reset を使用する方法 もう一つの手段として、 git reset コマンドを使用して取り消すことも可能です。 reset コマンドも restore 同様に、特定の時点まで変更を元に戻すコマンドです。 ( restore の方がより新しいコマンドです) 下記に実行例を記します。 $ git reset HEAD sample.txt Unstaged changes after reset: M sample.txt $ git status On branch main Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: sample.txt 無事にインデックスから削除できました。 こちらも先ほどまでと同様に、全ファイルを対象とする場合はファイル名無しで動作します。 $ git reset HEAD また、補足ですが今回使用した git reset は内部のオプションとして --mixed を実行した際と同じ動きとなっています。 (デフォルトで --mixed オプションが動作しています) $ git reset --mixed HEAD [ファイル名] まとめ Git入門ということで、 git add の取り消し方法についてご紹介しました。 Gitは異なるコマンドでもオプションによって同じ動きをするコマンドが多くあるので、ぜひ今回の記事も開発の際の参考にしていただければと思います。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
はじめに Room A PHP で NFC リーダーを実装する 僕が Illuminate を読む理由 テスト環境のインフラ・運用コストを下げたい話〜全部入りEC2を超えていけ 開発体験を爆上げするLaravel Dacapoマイグレーションサポートツールのススメ 実践!ユニットテスト入門 HTTPリクエストの行方 - Laravelがレスポンスを返すまで Laravel FormRequest にアクセサ機能を追加して、リクエストクラスをスッキリさせた 誰でも簡単に始められるBDD(ビーチ駆動開発)のススメ Room B FeatureToggle戦略と運用方法 今あらためて考える ~ PHPに型定義をする理由 ~ 実践PHPStan まとめ はじめに ラク スの配配メールで PHP エンジニアをしている、mrstsgk_rksです。 2022年8月27日(土)に PHPカンファレンス 沖縄が開催されました。 弊社からもエンジニアが参加いたしましたので、そのうち4名が参加したセッションのレポートをご紹介いたします! では、レポートスタート! なお、レポートはRoomAからBの順で開始時間順に記載しています。 Room A PHP で NFC リーダーを実装する report by id:Y-Kanoh speakerdeck.com 個人的に「ハードにつなぐ系は Python ばかりでズルい…」というのは共感です 笑 しかし、だからといって NFC リーダを PHP で扱って ICカード を読み取る発想はありませんでした 笑 発表では FFI というPHP7.4で導入された PHP から C言語 のライブラリを呼び出す仕組みを使って、 NFC リーダーのデータを読み込む方法についてデモを交えて解説いただきました。 FFI の存在は知っていましたが、具体的にどう使うのか想像がついていなかったので「なるほど・・・」と思いながら聴いていました。 Web以外での PHP の活用方法が広がると楽しいですね。 僕が Illuminate を読む理由 report by id:hirobex speakerdeck.com Laravelの本体であるIlluminateの読むメリットや、実例を交えて読み方の解説をしていただきました。 ドキュメントにないような便利メソッドの発掘ができたり、 OSS 貢献ができたりと Illuminateを読むと良いこと尽くしですね! テスト環境のインフラ・運用コストを下げたい話〜全部入りEC2を超えていけ report by id:Jazuma speakerdeck.com 株式会社 NetStat の中榮健二さん(@n_1215)による発表です。 本番環境では AWS の各種マネージドサービスやコンテナを利用する一方で、 社内環境やテスト環境ではインフラコストを抑えるためにEC2 インスタンス 一台に全てのMWをインストールして運用していたようです。 しかし、金銭的コストが抑えられる一方で運用保守コストがかさむ問題が発生しました。 そこで VPS の他、Heroku, GAEなど各種Paas系サービスが検討されました。 セッションでは最終的に選ばれたサービスには言及されませんでしたが、以下のような注意点が紹介されました。 インフラコストには人件費もあるので、金銭的コストだけに目を向けるとよくない DBサーバはコストが高いので、アプリケーションと同居させるのもあり cronや非同期処理も含めるとコストが高くなるので注意 開発体験を爆上げするLaravel Dacapo マイグレーション サポートツールのススメ report by id:Y-Kanoh speakerdeck.com LaravelのMigrationサポートライブラリ Laravel-Dacapo の生みの親であるucan さんの発表です。 不要になった マイグレーション 用ファイルが残る、最新のテーブル構成が読みづらいなどの課題があるLaravelの マイグレーション を、Laravel-Dacapoを使って YAML ファイルでわかりやすくまとめる方法を解説していただいています。 実践! ユニットテスト 入門 report by id:Jazuma speakerdeck.com プログラミングをするパンダさんによる発表です。 テストコードの書き方として、以下のようなテクニックが紹介されました。 テストケースを日本語で書く テストメソッドが何をしているのか説明する arrange / act / assertパターンで書く arranege: 事前条件 act: テスト対象メソッドを実行する assert: 検証観点 いろんなassertionを知る assertSame / assertException / assertContain等 setUp / tearDownで前後の処理をする 重複している処理を共 通化 することが目的 dataProviderでテストケースをまとめる 同じロジックを複数の入力値でテストする場合に使う ただし、早すぎる抽象化には要注意 コードの意図を明確に表現する、重複する処理を共 通化 する、早すぎる抽象化を避ける、等 プロダクトコードのノウハウを活かせる部分も多くありました。 HTTPリク エス トの行方 - Laravelがレスポンスを返すまで report by id:hirobex speakerdeck.com タイトルの通り、リク エス トを受けてからLaravelがレスポンスを返すまでの一連の流れを説明していただきました! HTTPの基本的な仕様から、 PHP がどうやってWebサーバーと連携しているか、DBとの連携はどうやっているか、などの深い内容まで解説していただきました! こういった仕様を理解することで、よりエンジニアとしてステップアップできそうだ、と感じる非常に勉強になるセッションでした! Laravel FormRequest にアクセサ機能を追加して、リク エス トクラスをスッキリさせた report by id:Y-Kanoh docs.google.com とある理由から アンチパターン が複数含まれたリク エス トを自サービス内のRequestクラスで整形することで扱いやすくした事例について紹介されていました。 詳しくは こちらの記事 に記載されているそうです! 誰でも簡単に始められるBDD(ビーチ駆動開発)のススメ report by id:Y-Kanoh speakerdeck.com そりゃ海でPC開いたら画面見えませんよね。 潮が満ちてきて海が迫ってき、最終的には暑さにやられるようです。 沖縄ならではの開発手法(?)ですが、BDDをやるかたは参考になると思います!! (進捗は期待しない方がいいそうです) Room B FeatureToggle戦略と運用方法 report by id:radiocat speakerdeck.com FeatureToggleは「コードを書き換えずにシステムの振る舞いを変更できるようにする開発手法」です。 用途に応じて大きく4つの種類があることが紹介されました。 Release Toggles トランクベース開発ですぐにマージできる 開発途中はフラグOFFにしておくことで本番環境に影響を与えずに開発できる Experiment Toggles A/Bテストや カナリア テストを実現するフラグ 特定のユーザーやグループに対してトグルをON/OFFする Ops Toggles システム動作の運用制御 パフォーマンスの影響などを制御し迅速に切り戻しできる Permissioning Toggles 特定のユーザーのみに機能を開放する 有料課金機能などで使われる 試験的なものではなく長期的に利用される 発表者の現場ではGitによるfeatureブランチで開発をしていましたが、メインブランチとfeatureブランチで取り込みが必要、コンフリクトも発生、リリース時にトラブルがあると切り戻しが発生するなどの課題があってFeature Toggleを導入するに至ったようです。 実際に導入してみると以下のような課題があったことが共有されました。 基本的にif分岐になるのでコード量が多くなる フラグONとOFFの両方の状態を担保しないといけないのでテストケースが増える リリース後に不要なコードを消さないといけない 最後の不要コード削除に関しては、事前に後で消す範囲を決めておいて一括で削除するライブラリを自前で開発されて対策されているようです。 その内容についてPHPerKaigi 2022で発表された資料が公開されています。 PHPコードを消すライブラリを作った - Speaker Deck この対策によってコード削除の手間を削減できて、Feature Toggleで中・大規模の新規開発でもトランクベースの開発を維持できるようになったとのことです。 FeatureToggleは以前から存在する概念で、発表の中で共有された課題があって導入に踏み切れないケースも多いと思っていました。 しかし、今回の発表のように課題に対するノウハウや事例が溜まってきており、今後広まっていく可能性を秘めていると感じました。 今あらためて考える ~ PHP に型定義をする理由 ~ report by id:hirobex speakerdeck.com PHP で型定義するメリットを フィードバックサイクル コーディングの生産性 コードのメンテナンス性 の3つの観点で語っていただきました。 どれも非常に魅力的なメリットばかりで、可能な限り型定義すべきだと思いました! 実践PHPStan report by id:Y-Kanoh tadsan.fanbox.cc PHPStanで型をつけて既存コードの型を検査することを目的に、 PHP での基本的な型の考え方から最近の PHP で発生する型宣言とPHPDocの選択問題などに触れておりました。 また、 PHP で表現しきれない”型”をPHPStanを使ってどう的確に表現し、さらに実行時に型がどうなっているかなどを確認しながら型安全なコードを実現する方法を説明いただきました。 (謎の PHP 用語”mixed”…) まとめ 今回はオンライン参加と会場参加の開催でした。 前年の PHPカンファレンス 沖縄2021では、オンラインのみの開催だったのですが 、今年はオンライン参加だけでなく会場参加でも参加できることに少し嬉しさを感じました。 弊社ではPHPTechCafeを毎月開催しています。 rakus.connpass.com エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
技術広報の yayawowo です。 今回は、 Linux 上でファイルや ディレクト リ検索時に利用する 『find コマンド』 について紹介します! find コマンドの基本をはじめ、活用例をコマンドサンプルを交えて説明させていただきます。 【目次】 find コマンドとは find コマンドの使い方 基本書式 オプション一覧 演算子/アクション一覧 find コマンドの活用例 終わりに ◆ Linux の理解をより深めたい方へ以下関連おすすめブログ ・ ls コマンド 【使い方 まとめ】 ・ よく使うLinuxコマンド一覧【最新版】 ・ sar コマンド【使い方 まとめ】 ・ iptables まとめ【Linux ファイアウォール】 ・ sed コマンド【使い方 まとめ】 ・ vi コマンド【使い方まとめ】 ・ Linuxのファイル操作でよく使うLinuxコマンド ・ 初心者のためのawkコマンド ・ 実務で使える!基本的なシェル(Linux)コマンドの話 ~forとsed~ ・ 【Linux】今振り返りたい、プロセスって何? find コマンドとは find コマンドは、検索するためのコマンドです。 ファイルや ディレクト リを検索する際に用います。 find コマンドの使い方 基本書式 find コマンドの基本書式は以下の通りです。 $ find 検索場所 [ オプション ] ファイル名 ファイルを検索するには、そのファイルがどこにあるのかを指定する必要があります。 また、find コマンドには多くのオプションがあります。 以下にまとめておきますので、用途に合わせて使い分けください。 オプション一覧 オプション 説明 -name ファイル名を指定検索 -iname 文字の大小を区別せず、ファイル名を指定検索 -type f ファイルのみを対象に検索 -type d ディレクト リを対象に検索 -type p 名前付きパイプを対象に検索 -empty ファイル容量が0のファイル/ ディレクト リを対象に検索 -size ファイル容量を指定検索 -path ファイルパスを指定検索 -ipath 文字の大小を区別せず、ファイルパスを指定検索 -newer 指定したファイルの更新日時後に更新された、ファイル/ ディレクト リを検索 -anewer 指定したファイルの更新日時後にアクセスされた、ファイル/ ディレクト リを検索 -mtime 日数 最後にデータが更新された日時を検索 -atime 日数 指定日数以前にアクセスされた、ファイル/ ディレクト リを対象に検索 -mmin 時間 指定分数に更新された、ファイル/ ディレクト リを対象に検索 - amin 指定分数にアクセスされた、ファイル/ ディレクト リを対象に検索 演算子 /アクション一覧 演算子 /アクション 説明 -a 複数条件検索 -and 複数条件(AND検索) -or 複数条件(OR検索) -not 条件不一致検索 -exec 検索結果に対してコマンドを実行 find コマンドの活用例 指定したファイル名を検索する(-name) # ファイル/ディレクトリ一覧を表示 localhost:/home/dir1# ls -1 dir1_1 dir1_2 sample.txt sample2.txt sample3.txt # 「sample2.txt」を指定検索 # findコマンドと-name localhost:/home/dir1# find /home/dir1/ -name sample2.txt /home/dir1/sample2.txt ファイルのみを対象に検索(-type f) # ファイル/ディレクトリ一覧を表示 localhost:/home/dir1# ls -1 dir1_1 dir1_2 sample.txt sample2.txt sample3.txt # ファイルのみを対象に検索 # findコマンドと-type f localhost:/home/dir1# find /home/dir1/ -type f /home/dir1/sample.txt /home/dir1/sample2.txt /home/dir1/sample3.txt ディレクト リを対象に検索(-type d) # ファイル/ディレクトリ一覧を表示 localhost:/home/dir1# ls -1 dir1_1 dir1_2 sample.txt sample2.txt sample3.txt # ディレクトリのみを対象に検索 # findコマンドと-type d localhost:/home/dir1# find /home/dir1/ -type d /home/dir1/ /home/dir1/dir1_1 /home/dir1/dir1_2 ファイル容量を指定検索(-size) # ファイル/ディレクトリ一覧を表示 localhost:/home/dir1# ls -la total 20 drwxr-xr-x 4 root root 166 Aug 26 16:47 . drwxr-xr-x 5 root root 100 Jul 5 2020 .. drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_1 drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_2 -rw-r--r-- 1 root root 13 Aug 26 16:48 sample.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample2.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample3.txt # ファイル容量が10byte以下のファイルを検索 # findコマンドと-size localhost:/home/dir1# find /home/dir1/ -size -10c /home/dir1/sample2.txt /home/dir1/sample3.txt 指定したファイルの更新日時後に更新された、ファイル/ ディレクト リを検索(-newer) ※2022/8/26を今日(当日)とします。 # ファイル/ディレクトリ一覧を表示 localhost:/home/dir1# ls -la total 20 drwxr-xr-x 4 root root 166 Aug 26 16:47 . drwxr-xr-x 5 root root 100 Jul 5 2020 .. drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_1 drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_2 -rw-r--r-- 1 root root 13 Aug 26 16:48 sample.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample2.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample3.txt # 「sample.txt」より後に更新したファイル/ディレクトリを検索 # findコマンドと-newer localhost:/home/dir1# find /home/dir1/ -newer sample.txt /home/dir1/dir1_1 /home/dir1/dir1_2 最後にデータが更新された日時を検索(-mtime 日数) ※日数の定義  今日:0  昨日:1 ※2022/8/26を今日(当日)とします。 # ファイル/ディレクトリ一覧を表示 localhost:/home/dir1# ls -la total 20 drwxr-xr-x 4 root root 166 Aug 26 16:47 . drwxr-xr-x 5 root root 100 Jul 5 2020 .. drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_1 drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_2 -rw-r--r-- 1 root root 13 Aug 26 16:48 sample.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample2.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample3.txt # 今日更新されたファイル/ディレクトリを検索 localhost:/home/dir1# find /home/dir1/ -mtime 0 /home/dir1/ /home/dir1/sample.txt /home/dir1/sample2.txt /home/dir1/sample3.txt /home/dir1/dir1_1 /home/dir1/dir1_2 # 最後にデータが更新されたファイル/ディレクトリを検索 # findコマンドと-mtime localhost:/home/dir1# find /home/dir/ -mtime 1 find: /home/dir/: No such file or directory 指定分数に更新された、ファイル/ ディレクト リを対象に検索(-mmin 時間) ※時間の定義  1分:1  6時間:60分×6時間=360  12時間:60分×12時間=720 ※2022/8/26を今日(当日)とします。 # ファイル/ディレクトリ一覧を表示 localhost:/home/dir1# ls -la total 20 drwxr-xr-x 4 root root 166 Aug 26 16:47 . drwxr-xr-x 5 root root 100 Jul 5 2020 .. drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_1 drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_2 -rw-r--r-- 1 root root 13 Aug 26 16:48 sample.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample2.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample3.txt # 30分以内に更新されたファイル/ディレクトリを検索 # findコマンドと-mmin localhost:/home/dir1# find /home/dir1/ -mmin -30 /home/dir1/ /home/dir1/sample.txt /home/dir1/sample2.txt /home/dir1/sample3.txt /home/dir1/dir1_1 /home/dir1/dir1_2 複数条件(AND検索)(-and) -type f と -mtime 日数 を組み合わせて検索します。 ※2022/8/26を今日(当日)とします。 # ファイル/ディレクトリ一覧を表示 localhost:/home/dir1# ls -la total 20 drwxr-xr-x 4 root root 166 Aug 26 16:47 . drwxr-xr-x 5 root root 100 Jul 5 2020 .. drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_1 drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_2 -rw-r--r-- 1 root root 13 Aug 26 16:48 sample.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample2.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample3.txt # 今日更新されたファイルのみを検索 # findコマンドと-and localhost:/home/dir1# find /home/dir1/ -type f -and -mtime 0 /home/dir1/sample.txt /home/dir1/sample2.txt /home/dir1/sample3.txt 複数条件(OR検索)(-or) -size を組み合わせて検索します。 # ファイル/ディレクトリ一覧を表示 localhost:/home/dir1# ls -la total 20 drwxr-xr-x 4 root root 166 Aug 26 16:47 . drwxr-xr-x 5 root root 100 Jul 5 2020 .. drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_1 drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_2 -rw-r--r-- 1 root root 13 Aug 26 16:48 sample.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample2.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample3.txt # ファイル容量が1byte以下又は、15byte以下のファイルを検索 # findコマンドと-or localhost:/home/dir1# find /home/dir1/ -size -1c -or -size -15c /home/dir1/sample.txt /home/dir1/sample2.txt /home/dir1/sample3.txt 条件不一致検索(-not) -type f と -not を組み合わせて、ファイル以外を検索します。 # ファイル/ディレクトリ一覧を表示 localhost:/home/dir1# ls -la total 20 drwxr-xr-x 4 root root 166 Aug 26 16:47 . drwxr-xr-x 5 root root 100 Jul 5 2020 .. drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_1 drwxr-xr-x 2 root root 37 Aug 26 16:49 dir1_2 -rw-r--r-- 1 root root 13 Aug 26 16:48 sample.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample2.txt -rw-r--r-- 1 root root 0 Aug 26 16:48 sample3.txt # ファイル以外を検索 # findコマンドと-not localhost:/home/dir1# find /home/dir1/ -not -type f /home/dir1/ /home/dir1/dir1_1 /home/dir1/dir1_2 終わりに いかがでしたでしょうか? 今回はファイルや ディレクト リ検索にて良く用いる、find コマンドの使い方をご紹介させていただきました。 find コマンドはオプションや、 演算子 等を使い分けることで様々な検索方法ができます。 Linux コマンドをまとめた ブログ もございますので、是非ご参考ください。 最後までお読みいただきありがとうございました! エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
はじめに こんにちは。新卒3年目のhy094です。 今回は、先日社内で開催したTypeScript勉強会の資料を公開します。 この資料は、前半は私が作成し後半は一年後輩のたぐち君が作成しています。 TypeScriptとは関係がないですが、たぐち君の記事(note)も紹介しておきます。 デスクトップの整理に悩んでいる方はぜひ見ていってください! note.com はじめに 前提 資料公開 スライドの中身 参考にさせていただいた書籍・サイト おわりに では、本題に入ります。 前提 TypeScript初心者 向けに作成した資料です JavaScript で書かれたコードのTypeScript移行を目的としています 移行に不要な箇所はあまり触れていません JavaScript の構文も紹介しています 資料公開 スライドの中身 スライドをみる時間がない方向けに、ざっくりどのような内容が書かれているかを記載します。 TypeScriptとは(4〜6ページ) TypeScriptにするメリット 型(8〜19ページ) プリミティブ型 文字列・数値・真偽値・undefined・null (BigInt・シンボルは省略) リテラル 型 object型 オブジェクト リテラル 配列 unknown, any, never ユニオン(合併)型・インターセクション(交差)型 基本的な構文(7,20,21ページ) 演算子 制御構文 関数(22〜26ページ) 関数宣言・アロー関数式 デフォルト引数 可変長引数 this引数 インターフェース(27〜32ページ) type interface 高度な型(33,34ページ) 型ガード 型 アサーション モジュールシステム(35〜39ページ) import・export type宣言 npmパッケージモジュール DefinitelyTyped 自作の型定義ファイル ビルド関連(40〜51ページ) コンパイル ・ コンパイル オプション tsconfig. json webpackタ スクラン ナー webpack.config.js 参考にさせていただいた書籍・サイト 主に以下の書籍・サイトを参考にさせていただきました。その他はスライドに記載しています。 プログラミングTypeScript プロを目指す人のためのTypeScript入門 サバイバルTypeScript これらは個人的に、TypeScriptの参考書3種の神器だと思っています。超オススメです。 おわりに 資料作成に際して、自身の知識がより深まりました。 なんとなく使っていたものを改めて説明するというのは、やはり難しいですね。 ありがたいことに勉強会自体は好評で、録画も社内で見ていただけているようです。 (勉強会後にアンケートを取っており、後日フロントエンドチームのnoteで公開予定です。) 録画の公開はできませんが、資料を見ていただき少しでもTypeScriptへの学びになれば嬉しいです! フロントエンドチームのnoteです。ぜひご覧ください! note.com エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
こんにちは!株式会社 ラク スの@kzak_24と申します。 インフラ開発部 SRE課に所属しております。 さて今回は、 現在 アサイ ンされている新規システムの開発プロジェクトにて、フロントエンドの技術選定を担当した時の経験 をまとめようと思います。 フロントエンドは未経験だった為、色々と試行錯誤を行いました。 未経験なりにどのような基準を設けて技術選定を行なったか 、皆さまの意思決定の参考になれば幸いです。 目次 SREチームの紹介 前提 チームの背景 検討内容と採用理由 言語 / FW 状態管理 スタイル テスト まとめ 最後に SREチームの紹介 まず始めに、少しだけSREチームについて紹介させてください。 ラク スのSREチームは2021年に発足した比較的新しい組織であり、下記の2つのチームに分かれています。 BP(Business Platform)チーム 社内業務システムの開発/保守/運用をメインに担当するチーム DevOpsチーム プロダクトを横断した自動化や運用改善をメインに担当するチーム 現在BPチームは4名、DevOpsチーム1名で構成されています。 私はBPチームに所属しており、このチームで今回のプロジェクトをスタートさせました。 ラク スのSREチームにご興味ある方は、以下もご参考になさってください。 ・ SREエンジニア | エンジニア職種紹介 | 株式会社ラクス 中途採用 ・ Webアプリケーションエンジニア/Go, TypeScript | エンジニア職種紹介 | 株式会社ラクス 中途採用 前提 今回は、以下のような前提の元で技術選定を行いました。 新規システムとして過去の負債がないまっさらな状態から開発をスタートできる できるだけモダンな技術を使用する(社内の ベンチマーク 的な意味を込めて) 開発するアプリケーションは SPA(Single Page Application) の構成にする 一部ページで SSR (Server Side Rendering)が必要になる チームの背景 バックエンド専門メンバーのみで、フロントエンドの経験は乏しい モダンなフロントエンドの開発経験は、ほぼない これらの前提を踏まえて、今回のプロジェクトにおけるフロントエンドの技術選定については、経験値の低さをカバーすることを重要視し、情報収集のしやすさや学習モチベーションの維持を含めた 「学習コスト」 を最優先することとしました。 また次点で以下の3点を優先することとしました。 社内の利用実績 トレンド 保守性 ※ 2022年 8月 24日 追記 SREチームでフロントエンドの技術選定をしている理由についてのコメントを頂いたので、SREチームの背景を交えて経緯について補足させていただきます。 SREチームの紹介 に記載した通り、BPチームは社内向けの共通基盤の開発・運用を担当しており、アプリケーションエンジニアとしても活動しています。 SREにアプリケーションエンジニアがいる理由は、SREチームが新たなノウハウを各サービスへ展開することをミッションの1つとしている為です。 ラク スではサービスごとに開発チームが存在しており、技術導入なども各チームで判断していますが以下のような課題もあります。 サービスの機能開発と並行稼働の為、導入が思うように進まない そこで、SREチームが社内向けの共通基盤の開発・運用を通し、先行して新しい技術の調査・導入を行うことで、そのノウハウを各サービスに展開し、技術導入を推進するという動きをしています。 その際、以下のように役割分担しています。 BPチーム:技術調査・導入 DevOpsチーム:各サービスへの展開 こういった背景からアプリケーションの開発知識が必要になるので、SREチームにアプリケーションエンジニアが在籍しています。 今回ご紹介するフロントエンドの技術選定は、BPチームの技術調査・導入の活動についての事例となります。 チームの背景 に記載した通り、バックエンド専門のメンバーのみだったので、フロントエンドはフロントエンド専門チームに任せるか?といった議論もありましたが、「過去事例に囚われず、フラットに検討すべき」という判断と「フロントエンドにもチャレンジしたい」という思いから、敢えて自分たちで担当することにしました。 検討内容と採用理由 今回は、以下4つを検討しました。 言語 / FW 状態管理 スタイル テスト 言語 / FW 言語に関しては、近年 デファクトスタンダード になりつつあることと、バックエンド専門で静的型付け言語に慣れているメンバーが多いということで、TypeScriptに決定しました。 また、FWは次の2つから検討しました。 React Vue.js 検討にあたり、判断材料とする為に次のようなことを実施しました。 フロントエンド専門チームへの ヒアリ ング チュートリアル の実践 その結果、今回の選定方針をもとに以下のような比較をすることができました。 React Pros JSX記法のメンバー受けがよく、学習モチベーションが保てそう 関数 コンポーネント 主体で宣言的にかけるので、コードが読みやすく、保守性が高い 直近でリリースした社内の他プロダクトで利用実績がある Cons Vue.jsと比べると学習コストはやや高い ドキュメントの充実度は低い Vue.js Pros 利用者が多く、情報が得られやすいので学習コストが低い 日本語ドキュメントが多い シンプルな設計で拡張性が高い 社内での利用実績がReactより多い Cons SFC 記法のメンバー受けがよくなく、学習モチベーションは低い 世界的なトレンドはReactに劣る 決定内容と理由 決定内容 Reactを採用する 理由 チーム内での評判がよく、モチベーション高く学習を続けていくことができると考えました。 また、保守性の高さや コンポーネント の再利用性もReactの方がチーム内での評価が良かったことも理由です。 Reactを採用するにあたり、 SSR の実現の為に Next.js も採用しました。 状態管理 状態管理に関しては、Reactを使用することを前提として代表的なライブラリである下記の3つから検討しました。 Redux Recoil React Context 状態管理のライブラリについては、主に公式ドキュメントやWebの記事などから情報を収集し、比較検討を行いました。 Redux Fluxベースの状態管理ライブラリです。 Pros 柔軟性が高い Reduxが定めるベストプ ラク ティスのRedux ToolKitがある 1つのグローバルなストアにStateを保持するので管理が容易 Cons 学習コストが高い 今回のプロジェクトで開発するアプリケーションにはToo Muchである Recoil Meta社製の状態管理ライブラリです。 Pros Atom という単位で一意なキーをもったグローバルStateを保持するので、理解しやすい 学習コストが低い割に、機能的には十分 Cons Atom が増えすぎると管理が難しくなる まだメジャーバージョンリリースしていない(執筆時点でのLatestはv0.7.5) React Context Reactが標準で提供しているContext API です。 Pros React標準なので、導入ハードルが低い Hooks( useContext )が提供されているので、使い勝手が良い Cons 管理するStateが増えてくるとProviderのネストが深くなり、視認性が悪くなる 祖先 コンポーネント まで辿ってツリーを更新する為、頻繁に レンダリング が発生してしまう 決定内容と理由 決定内容 Recoilを採用する 理由 今回開発するアプリケーションの規模から、ReduxではToo Much、React Contextでは若干不足と考えたので、Recoilを採用しました。 また、基本的に Atom をHooksで操作するだけのシンプルさや学習コストの低さも魅力的でした。 メジャーバージョンのリリースはまだでしたが、実際にプロダクション利用している他社事例もあった為、その点に関しては問題なしと判断しました。 スタイル スタイルに関しては、まず CSS の管理方法について、次のような思いがありました。 CSS に詳しいメンバーがいない為、なるべく CSS ファイルの管理は避けたい スコープはできるだけローカルに閉じて、堅牢性をあげたい 上記の思いを踏まえつつ、方針を考慮した結果、下記の2つから検討しました。 CSS Module styled-components(CSS in JS) 簡単なプロトタイプを実装し、使い勝手や学習コストを比較検討しました。 CSS Modules CSS ファイルをJSからimportしてスタイルを当てる手法です。 Next.jsでは標準でサポートされています。 Pros Next.jsに標準でサポートされている為、導入コストが低い コンポーネント 単位でスコープを閉じられる Cons CSS ファイルを管理することになる 社内に利用実績がない styled-components CSS in JSのライブラリです。 Pros コンポーネント のコードと同居させられるので、スコープについてほぼ考えなくて良い 直近でリリースした社内の他プロダクトで利用実績がある Cons コンポーネント に依存したカスタマイズをするので、移行が難しい 静的な CSS よりもパフォーマンスが低い 決定内容と理由 決定内容 styled-components( CSS in JS)を採用する 理由 JSファイル内に CSS を記述できるため、以下の通り前提の思いを2つともクリアできる点が決め手でした。 スコープについてほぼ考えなくて良くなる CSS ファイルを作成しなくても良い また、社内でも利用実績があり、情報収集の容易さという点でもメリットがありました。 テスト 最後にテストに関してですが、まずフロントエンドのテスト方針をどのように設定すべきか全く知識がなかった為、社内のフロントエンドチームに ヒアリ ングしました。 そこで Testing Trophy の考え方を教えていただきました。 Testing TrophyとはReact Testing Libraryの作者であるKent C. Dodds氏が提唱する JavaScript のテスト方針です。 今回はその考えに則り、Unit Test及びIntegration Testの層を厚くする方針としました。 その前提の元、テストライブラリは下記の2つを検討しました。 React Testing Library Enzyme テストランナーについては、ほぼ デファクトスタンダード になってきていると思われることと、Next.jsに標準で組み込まれていることから、 Jest を採用しました。 テストは、スタイルの検討の際に実装していたプロトタイプの中で使用し、使い勝手や学習コストを比較検討しました。 React Testing Library Kent C. Dodds氏によるReactテストライブラリです。 Pros Next.jsの 公式ドキュメント でJestと合わせた構成が推奨されている 実際にユーザーにどう見えるかを基準にしたBDD寄りの考え方がチーム内で評判が良い スナップショットテストを実施でき、改修時のリスクを減らせる 直近でリリースした他プロダクトで利用実績がある Cons Enzymeに比べるとコードの記述量が多い Enzyme Airbnb 社製のReactテストライブラリです。 Pros shallow renderのテストは書きやすい コードの記述量は比較的少なくできる コンポーネント のpropsやstateに直接アクセスできる Cons ユーザー目線ではないテストができ上がりがち 決定内容と理由 決定内容 React Testing Libraryを採用する 理由 ユーザーにどう見えるかを基準にしたBDD寄りの方針で作られています。 そのため、本質的なテストをすることができる点に関して、チーム内で評価されたことが決め手でした。 また、関数などのUnit TestはJestで、 コンポーネント 同士のIntegration TestはReact Testing Libraryでという明確な使い分けができ、Unit Test、Integration Testを充実させるテスト方針とマッチすると考えました。 まとめ 最終的に今回採用した技術は以下になります。 言語 / FW 状態管理 スタイル テスト ・TypeScript ・React ・Next.js ・Recoil ・styled-components( CSS in JS) ・Jest ・React Testing Library 最後に 最後までご覧いただきありがとうございます。 今回は、フロントエンド未経験のSREエンジニアが技術選定を担当した経験についてご紹介しました。 技術選定はシステム要件、チームの背景、スケジュールなど様々な要因を考慮する必要があり、非常に良い経験となりました。 SREチームではフロントエンドだけではなく、バックエンドではGoを使用した フルスクラッチ 開発や、 AWS EKSを使用した Kubernetes 基盤の構築など様々な取り組みを進めております。 今回紹介したこと以外にもたくさんの情報を発信していけるように、今後も取り組んで参ります。 ◆ 直近で開催予定の採用イベントをご紹介! career-recruit.rakus.co.jp career-recruit.rakus.co.jp エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 https://rakus.hubspotpagebuilder.com/visit_engineer/ rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
はじめに 皆さん、こんにちは、kirrksです。 今回は一度は聞いたことある「プロキシ」について、 プロキシの仕組みや種類 利用するメリット/デメリット 注意点 など、簡単に解説していきます。 この記事を読んで「プロキシ」を少しでも理解して頂ければ幸いです。 目次 はじめに 目次 プロキシとは プロキシの仕組み プロキシのメリット プロキシのデメリット 利用上の注意点 プロキシの種類 まとめ プロキシとは プロキシとは、主に「クライアント」から「サーバ」にアクセスする際、「クライアントの代理」として接続を行うサーバのことを指します。 プロキシ(Proxy)は、直訳で「 代理人 」「代理」「代わり」などの意味を持ちます。 プロキシには、目的別に様々な種類が存在しますが、一般的には利用者(クライアント)とWebサーバの中間でHTTP通信を代理するWebプロキシ( フォワ ードプロキシ)を指すことが多いです。 プロキシの仕組み これから、プロキシの仕組みについて、「クライアント」から「Webサーバ」へアクセスする流れを用いて見ていきましょう。 なお、ここでは「プロキシサーバを経由しない通信」「プロキシサーバを経由する通信」の流れに分けて確認していきます。 プロキシサーバを経由しない通信 まず、クライアントからWebサーバに通常アクセスする流れです。 クライアント端末のブラウザからサイトをリク エス トする リク エス トがWebサーバに届く Webサーバがリク エス トに対応したページをクライアントへ返す クライアント端末のブラウザにサイトが表示される 以上のように、通常はクライアントが直接Webサーバにリク エス トをします。 プロキシサーバを経由する通信 次に、プロキシサーバを経由してアクセスする流れを見ていきましょう。 クライアント端末のブラウザからサイトをリク エス トする リク エス トをプロキシが受け取る プロキシがWebサーバへリク エス トを送る Webサーバがリク エス トに対応したページをプロキシに返す プロキシはWebサーバから返ってきたページをクライアント端末に渡す クライアント端末のブラウザにサイトが表示される このように、クライアント端末はWebサーバへ直接リク エス トを送るのではなく、プロキシに最初リク エス トを送ります。 上記2つの通信の流れの違いは、以下となります。 プロキシを介している場合、Webサーバはクライアントの情報がわからない Webサーバがわかる情報は、プロキシの情報のみ 以上のように、クライアントからWebサーバへのリク エス トをプロキシが代わりに行っているのです。 プロキシのメリット ここでは、プロキシの利用によるメリットを紹介していきます。 匿名性が確保できる プロキシの利用は、匿名性を確保できることからセキュリティの強化につながります。 クライアント端末から直接Webサーバにアクセスした場合、 IPアドレス などの情報は接続先(Webサーバ)に記録されます。 一般家庭の通信は、接続ごとに IPアドレス が変わるため問題ありません。 しかし、専用回線を使用する企業には、 サイバー攻撃 の可能性があります。 悪意のあるサイトにアクセスした場合、アクセス元を把握され サイバー攻撃 につながる可能性があります。 しかし、プロキシを経由すれば端末は直接接続されないため、情報が接続先に伝わりません。 プロキシ上に アクセスログ が残る プロキシ上にログが残ることも、プロキシサーバを利用する大きなメリットです。 プロキシサーバを使用すれば、どのサイトにアクセスしたのかなどのデータがログに記録されます。 そのため、 どのような人物がどういったサイトを閲覧しているのか 不正なアクセスが行われるのはどこからなのか などの情報を残すことができます。 これらのことを記録しておくことで、万が一 サイバー攻撃 などを受けた場合などにもログを解析することによって適切に対処することが可能になります。 サーバの負担を分散できる サーバの負担を分散できることも、プロキシサーバの大きなメリットです。 特定のサイトへアクセスが集中しないよう、複数サーバへ振り分けることができる「ロードバランシング」という機能を持たせることが可能です。 このような機能によってネットワークやサーバ負担を軽減させることができ、通信速度を向上させる効果もあります。 このように、プロキシサーバはユーザーが快適に利用できる環境を整える役割も担っています。 キャッシュサイト機能で表示の高速化 プロキシにキャッシュが残っていると、コンテンツの表示が早くなることも大きなメリットです。 Webサーバにリク エス トを送信する必要がなくなり、同時にWebサーバからコンテンツを受信する時間も省略することができ、その分だけ表示スピードが早くなります。 ウイルスチェックができる プロキシでは、ウイルスチェックも行うことができます。 クライアント端末ではなく、プロキシ上でウイルスチェックができるため、運用する上でメリットがあるのです。 ウイルスに感染すると、個人情報の流出や様々なトラブルにつながる可能性があります。 個人情報の流出は企業であれば顧客の信頼を一瞬で失ってしまうことになります。 そのようなことを防ぐためにも、ウイルスチェックを行うことが必要です。 対策することによって、社内ネットワークへのウイルスの侵入を未然に防ぐことができ、安全性を向上させることができます。 プロキシのデメリット ここでは、プロキシの利用によるデメリットを紹介していきます。 不正サイトへ誘導される可能性がある プロキシが不正なサイトへの誘導を行ってしまう可能性があることは、デメリットの一つです。 例としては、プロキシに対して攻撃が仕掛けられ、偽のサイトや フィッシング詐欺 などのサイトへ誘導してしまうものなどがあります。 こういった場合にはユーザーのリク エス トとは別のサイトへプロキシが誘導してしまうことになるのです。 それによって、誘導をしたサイトでユーザーの個人情報が抜き取られたり、詐欺に遭うなどの被害をもたらしてしまう危険性があります。 接続履歴が見られる可能性がある プロキシの接続履歴が見られる可能性があることも、デメリットの一つです。 上述したように、プロキシ上には様々なデータ(ログ)が残っているため、攻撃しようとする者によってこれらの情報を見られてしまう危険性があります。 ログを確認されることで、個人情報の漏洩やアクセス履歴から迷惑メールの対象となってしまう可能性もあります。 このように、接続履歴をチェックされるとユーザーにも被害が出る危険性があることは、あらかじめ把握しておく必要があります。 情報が盗まれる可能性がある プロキシを利用すると、サーバを経由してやりとりしている情報を盗まれる可能性があることも、デメリットになります。 例としては、悪意のある人物が意図的にプロキシを設置した場合や、 ハッカー によってハッキングされたような場合にはアクセスの際に送受信した情報を抜き取られることもあり得ます。 このような情報には様々な個人情報が含まれている場合も多く、ユーザーに被害がおよぶ危険性があります。 利用する際にはサーバだけではなく、アクセス先のセキュリティ対策がしっかり行われているかどうかについてもよく確認しておきましょう。 サイトによっては通信速度が低下する プロキシのメリットに表示速度の速さをあげましたが、それはキャッシュが残っているときの話です。 キャッシュのない場合には、通信速度が遅くなる可能性があります。 利用上の注意点 ここでは、プロキシを利用する際の注意点を紹介していきます。 安全な非公開プロキシを利用する 誰でも利用できるプロキシサーバを公開プロキシと言います。 公開プロキシには、利用者の個人情報を抜き取る「悪意のあるプロキシ」を設置している可能性があります。 プロキシサーバを利用する際は、信頼できる提供元の非公開プロキシを利用するようにしましょう。 認証設定を行う プロキシサーバを購入し、自分で構築したい人は、必ずIDとパスワードによる認証を有効化しておきましょう。 もし、有効化を怠ると、誰でもアクセスできる状態になります。 不特定多数が利用できるプロキシサーバはリスクが高く、ウイルス感染、 個人情報流出 、サイバー犯罪のアクセス経路に利用されてしまいます。 必要な場合に限り使用する プロキシサーバは必ず使用しなくてはいけないものではありません。 どうしても必要なときだけ利用するようにしましょう。 それだけで個人情報漏洩や悪意ある サイバー攻撃 を受けてしまうリスクを減らすことができます。 プロキシの種類 ここでは利用目的により、種類が異なるプロキシを簡単に紹介していきます。 フォワ ードプロキシ Webプロキシサーバとも呼ばれ、クライアントとWebの間に設置し、利用者側に位置しています。 ファイアウォール によるアクセス制限の際に、外部ネットワークへの接続を目的として利用される傾向が多いです。 リバースプロキシ 「逆プロキシ」とも呼ばれ、利用者とWebの間に設置しますが、 フォワ ードプロキシとは異なり、Webサーバ側に位置します。 主にWebサーバの負荷軽減を目的としています。 透過型プロキシ ネットワーク側の特定ポートに向けて設置するプロキシです。 利用者は、通信の迂回路を作成できないため、他のネットワークの使用ができません。 端末でプロキシを設定しなくても適用できるため、従業員が多い企業で利用されるのが一般的です。 キャッシュサーバ プロキシには、インターネット接続の際にデータをキャッシュとして保管する機能があり、2回目以降に同じサーバへアクセスする際は、高速でサイトが表示されます。 さらに、同じプロキシを利用している端末が1度でもサイトにアクセスすれば、それ以外のユーザーも高速で接続できます。 まとめ いかがでしたでしょうか? 今回はプロキシについてご紹介させていただきました。 プロキシの役割が少しでもわかったのではないでしょうか。 改めまして、本記事がITを学ぶ方にとって、少しでもお役立ちできれば幸いです。 最後までお読みいただきありがとうございました。 参考 プロキシとは?仕組みやメリットからプロキシの種類までを解説! | IT SPice | CTCエスピー(株) プロキシとは?主なメリットやデメリット、注意点 から種類まで徹底解説! | ITトレンド プロキシサーバとは?仕組みやメリット・デメリットを詳しく解説! | DIGITAL SHIFT TIMES エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
はじめに 皆様こんにちは。 インフラ開発課でインフラエンジニアとして勤務しておりますryskwです。 ラク スではメールを主に扱うサービスが多くあります。 そのため、メールに関する知識は業務に欠かせないものとなっています。 今回は、そんなメールに関する ソフトウェアとして有名な Postfix (ポストフィックス) を取り上げたいと思います。 本記事を読むことで、 Postfix を使用したメールサーバの基本的な構築をしたいという方 のお役に立てれば幸いです。 目次 はじめに 目次 Postfixとは Postfixのインストール Postfixの設定 設定ファイルのバックアップ Postfixで使用するドメイン名の指定 Postfixで使用するインターフェースの指定 Postfixで拒否したいメールの設定 Postfixのバージョン非表示設定 Postfixでメール送信 おまけ FromアドレスとエンベロープFrom メール受信にはDovecot 最後に 参考 Postfix とは Postfix は フリーソフトウェア のメール転送エージェント(MTA)であり、 Linux などの UNIX 系システムで実行されます。 UNIX で古くから使用されてきた Sendmail に代わるものとして開発されたようです。 Postfix のホームページでは Sendmail ライクに見えますが、より安全、高速、設定しやすいことなどをメリットとして挙げています。 ※メール転送エージェントとは、メールの配送(送信)を行うメールサーバ  ( SMTP サーバと言ったりもしますね)の中で、文字通りメールの転送を担うプログラムです。  受信したメールを相手方に送信する(振り分ける)メールサーバの中でも中心的な役割を持っています。 また、メールサーバと言うと送受信できるようなイメージを持ちますが、実際にはメール受信には受信用のサーバが必要となります(POPサーバや IMAP サーバ)。 Postfix は受信サーバとしての役割はないため、受信用サーバを構築したい場合は、別途ソフトウェアを併せてインストールする必要があります。 Postfix のインストール それでは、 Postfix を利用したメールサーバの構築を実際に行ってみましょう。 Postfix は UNIX 系のOSで動作するため、本記事では Linux OSの中から Alma Linux を使用してインストールしていきます。 ホスト名は smtp.test.hdomain としています。 [ root@smtp ~ ] # cat /etc/redhat-release AlmaLinux release 8 . 5 ( Arctic Sphynx ) [ root@smtp ~ ] # uname -a Linux smtp. test .hdomain 4 . 18 .0-348.el8.x86_64 #1 SMP Tue Nov 9 06:28:28 EST 2021 x86_64 x86_64 x86_64 GNU/Linux [ root@smtp ~ ] # では、 Postfix をインストールしていきましょう。 AlmaLinux 8.5 では、標準でバージョン 3.5.8-4 の Postfix がインストールされるようです。 yum install コマンドで Postfix のインストールを行います。 [ root@smtp ~ ] # yum install postfix メタデータの期限切れの最終確認: 0:02:01 時間前の 2022 年 08 月 08 日 23 時 36 分 39 秒 に実施しました。 依存関係が解決しました。 ============================================================================================================================================================================================================================================= パッケージ アーキテクチャー バージョン リポジトリー サイズ ============================================================================================================================================================================================================================================= インストール: postfix x86_64 2:3. 5 .8-4.el8 baseos 1 . 5 M 依存関係のインストール: libicu x86_64 60 .3-2.el8_1 baseos 8 . 8 M トランザクションの概要 ============================================================================================================================================================================================================================================= インストール 2 パッケージ ダウンロードサイズの合計: 10 M インストール後のサイズ: 37 M これでよろしいですか? [ y/N ] : y パッケージのダウンロード: ( 1 / 2 ) : postfix-3. 5 .8-4.el8.x86_64. rpm 9 . 4 MB/s | 1 . 5 MB 00:00 ( 2 / 2 ) : libicu-60.3-2.el8_1.x86_64. rpm 16 MB/s | 8 . 8 MB 00:00 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 合計 6 . 8 MB/s | 10 MB 00:01 AlmaLinux 8 - BaseOS 2 . 8 MB/s | 3 . 4 kB 00:00 GPG 鍵 0xC21AD6EA をインポート中: Userid : " AlmaLinux <packager@almalinux.org> " Fingerprint: E53C F5EF 91CE B0AD 1812 ECB8 51D6 647E C21A D6EA From : /etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux これでよろしいですか? [ y/N ] : y 鍵のインポートに成功しました トランザクションの確認を実行中 トランザクションの確認に成功しました。 トランザクションのテストを実行中 トランザクションのテストに成功しました。 トランザクションを実行中 準備 : 1 / 1 インストール中 : libicu-60.3-2.el8_1.x86_64 1 / 2 scriptletの実行中: libicu-60.3-2.el8_1.x86_64 1 / 2 scriptletの実行中: postfix-2:3. 5 .8-4.el8.x86_64 2 / 2 インストール中 : postfix-2:3. 5 .8-4.el8.x86_64 2 / 2 scriptletの実行中: postfix-2:3. 5 .8-4.el8.x86_64 2 / 2 検証 : libicu-60.3-2.el8_1.x86_64 1 / 2 検証 : postfix-2:3. 5 .8-4.el8.x86_64 2 / 2 インストール済み: libicu-60.3-2.el8_1.x86_64 postfix-2:3. 5 .8-4.el8.x86_64 完了しました! [ root@smtp ~ ] # これで無事インストールが完了しました! Postfix の設定 続いて Postfix の基本的な設定を行っていきます。 Postfix の基本の設定を行うには、 /etc/postfix/main.cf という設定ファイルがあるので、そのファイルで必要となるパラメータを定義していきます。 ここでは、検証環境を構築する上で必要最低限となる設定のみ取り扱っています。 もし必要があれば Postfix のホームページからより細かな設定について記載がありますので、そちらもどうぞご確認ください。 設定ファイルのバックアップ では、 Postfix の設定ファイルを修正していきましょう。 まずは、元の設定ファイルのバックアップを取得しておきましょう。 [ root@smtp ~ ] # cp -p /etc/postfix/main.cf /etc/postfix/main.cf.org [ root@smtp ~ ] # ls /etc/postfix/main.cf.org /etc/postfix/main.cf.org [ root@smtp ~ ] # 設定ファイルを修正していきます。 [ root@smtp ~ ] # vi /etc/postfix/main.cf Postfix で使用する ドメイン 名の指定 まずは myhostname という設定を探しましょう。 ドキュメントには Postfix をインストールしたマシンの完全修飾 ドメイン 名(いわゆる FQDN )を指定する、とあります。 94~95行目に設定が記載されていると思いますので、その下に新たに Postfix をインストールしたマシンのホスト名を追記しましょう。myhostnameを設定することでメールアドレスの@マーク以降に入る ドメイン を指定できます。 #myhostname = host.domain.tld #myhostname = virtual.domain.tld myhostname = smtp.test.hdomain → 追記した設定 あるいは、 mydomain という設定で ドメイン 名を設定することもできます。 mydomainに ドメイン 名を指定しておくことで、main.cf内でmydomainが変数のように扱われ、それを元にmyhostnameで FQDN を生成することができます。 今回構築している検証環境を例に挙げると smtp : ホスト部 test.hdomain: ドメイン 部 となるため、mydomainにはtest.hdomainを記載します。 恐らく、デフォルトの設定ファイルでは102行目あたりに記載があるはずです。 #mydomain = domain.tld mydomain = test.hdomain → 追記した設定 次にメールの配送先の指定を行います。 mydestination では別のサーバではなく、 Postfix をインストールしているマシンに配信する際の ドメイン を指定します。 サーバでは大抵rootユーザ宛などシステムメールが配信されていたりするため、ローカルで配信されるメールの配送先として自身のホスト名を指定しておきます。 構築するサーバが ドメイン 全体のメールサーバである場合は「mydomainもリストする必要がある」、とドキュメントに記載されておりますので、ここは後々のことも考えてデフォルトで指定されている設定は コメントアウト し、mydomainも指定されているものをアンコメントして有効化しておきましょう。 #mydestination = $myhostname, localhost.$mydomain, localhost → デフォルトではここが有効になっているためコメントアウト mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain → mydomainがリストされているこの行を有効化 #mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain, # mail.$mydomain, www.$mydomain, ftp.$mydomain Postfix で使用するインターフェースの指定 続いて、 Postfix がメールを受信する際のインターフェースを設定しましょう。 デフォルトではローカルホストのみとなっているため、外部からのメールを受け取れないようになっています。 inet_interfaces の設定でローカルホストだけでなくすべてのネットワークインターフェース(このサーバが持つ IPアドレス )で受信が可能となるように、以下のように設定を変更しておきしょう。 ※より安心な設計として、main.cfはデフォルトの設定のままにしておき、  master.cfという設定ファイルで明示的に IPアドレス を指定する、という方法もあります。  しかしながら、今回はmain.cfを主に修正しているのでこの方法で進めます。 inet_interfaces = all → この行を有効化 #inet_interfaces = $myhostname #inet_interfaces = $myhostname, localhost #inet_interfaces = localhost → デフォルトではここが有効になっているためコメントアウト Postfix で拒否したいメールの設定 安心なメールサーバ構築のためには、意図しない ドメイン へメールを送らないように設定しなればなりません。 もしも他人が使用できるグローバルな環境で、どの ドメイン にも送れてしまうようなメールサーバを構築してしまった場合、 スパムメール を送るリレーサーバとして悪意あるユーザから悪用されてしまうことが考えられます。 そこで、 Postfix の設定の中に、これまで設定してきた ドメイン やホスト名に合致しない宛先にメールを送ろうとした場合に拒否する設定がありますので、そちらも設定しておきます。 local_recipient_maps という設定に有効な受信者としての ドメイン をリストしておくことで、受信者チェックを行いmydestinationなどで設定した ドメイン に一致しないローカルユーザへのメールを拒否することができます。 デフォルト設定から触らなくとも問題はないですが、わかりやすいので明示的にアンコメントして有効化しておきましょう。 local_recipient_maps = unix:passwd.byname $alias_maps → この行を有効化 #local_recipient_maps = proxy:unix:passwd.byname $alias_maps #local_recipient_maps = Postfix のバージョン非表示設定 さて、 Postfix を使用してメールサーバを構築する準備をしてきましたが、あらゆるソフトウェアには将来的に 脆弱性 が生じる可能性があります。 どのソフトウェアのどのバージョンを使用してサーバが構築されているか、ということが知られてしまうと、そのソフトウェアやバージョンに 脆弱性 があった場合、外部公開しているサーバの 脆弱性 を攻撃されてしまうことで何らかの影響が生じてしまう可能性があります。 そのため、基本的には使用しているソフトウェアは外部から接続された場合にバージョンがわからないようにしておくことがベストです。 どのバージョンの Postfix を使用しているかが外部にわからないように、 Postfix への接続時にバージョン情報が表示されないよう、以下を設定しておきましょう。 #smtpd_banner = $myhostname ESMTP $mail_name #smtpd_banner = $myhostname ESMTP $mail_name ($mail_version) smtpd_banner = $myhostname ESMTP $mail_name unknown → 追記した設定 また、 Postfix を使用してメールの送信した記録をログファイルで確認したい時があると思いますので、最後にログの設定をしておきます。 main.cfの末尾に、以下のように追記することで、 /var/log/maillog にログが残るようにします。 syslog_facility = mail 以上で、 Postfix の基本的な設定は完了です。 少し長かったでしょうか。お疲れ様でした。 最後に Postfix を再起動して設定完了です。 [ root@smtp ~ ] # systemctl restart postfix [ root@smtp ~ ] # systemctl status postfix ● postfix.service - Postfix Mail Transport Agent Loaded: loaded ( /usr/lib/systemd/system/postfix.service ; disabled ; vendor preset: disabled ) Active: active ( running ) since Wed 2022-08-10 16:11:24 JST; 7s ago Process: 15565 ExecStart =/usr/sbin/postfix start ( code =exited , status = 0 /SUCCESS ) Process: 15563 ExecStartPre =/usr/libexec/postfix/chroot-update ( code =exited , status = 0 /SUCCESS ) Process: 15559 ExecStartPre =/usr/libexec/postfix/aliasesdb ( code =exited , status = 0 /SUCCESS ) Process: 15557 ExecStartPre =/usr/sbin/restorecon -R /var/spool/postfix/pid/master.pid ( code =exited , status = 255 ) Main PID: 15634 ( master ) Tasks: 3 ( limit: 10645 ) Memory: 5 .1M CGroup: /system.slice/postfix.service tq15634 /usr/libexec/postfix/master -w tq15635 pickup -l -t unix -u mq15636 qmgr -l -t unix -u 8 月 10 16:11:23 smtp. test .hdomain systemd [ 1 ] : Starting Postfix Mail Transport Agent... 8 月 10 16:11:23 smtp. test .hdomain restorecon [ 15557 ] : /usr/sbin/restorecon: lstat ( /var/spool/postfix/pid/master.pid ) failed: No such file or directory 8 月 10 16:11:24 smtp. test .hdomain postfix/master [ 15634 ] : daemon started -- version 3 . 5 . 8 , configuration /etc/postfix 8 月 10 16:11:24 smtp. test .hdomain systemd [ 1 ] : Started Postfix Mail Transport Agent. [ root@smtp ~ ] # 問題なく起動していればOKです。 Postfix でメール送信 それでは、基本的な設定が終わったのでメールの送信をしてみましょう! 今回は、構築したサーバとは別にメールを受信できるサーバを用意しました。 また、「ryskw」というユーザを用意したので、そのユーザ宛にメールを送信してみます。 以下のように sendmail コマンドでメールを送信してみましょう。 [ root@smtp ~ ] # sendmail ryskw@ [ 送信先のホスト名 ] .hdomain → 送信先のメールアドレス。 [ ユーザ名 ] @ [ 送信先のサーバ ] となる From:ryskw@smtp. test .hdomain → 送信元のメールアドレス To:ryskw@ [ 送信先のホスト名 ] .hdomain → 送信先のメールアドレス Subject:Postfix test → メールの件名 test → メールの本文 . → 本文を書き終えたら「.」を打ってEnter [ root@smtp ~ ] # これでメールが送信されたはずです。 Postfix の設定でメールの送信ログが /var/log/maillog に出力されるように設定したので、ログを確認してみましょう。 [ root@smtp ~ ] # cat /var/log/maillog ------------以下のようなログがあればok------------ Aug 10 17:45:03 smtp postfix/pickup [ 15635 ] : 1CEAB1002B7E: uid = 0 from = < root > Aug 10 17:45:03 smtp postfix/cleanup [ 15677 ] : 1CEAB1002B7E: message-id =< 20220810084503 .1CEAB1002B7E@smtp. test .hdomain > Aug 10 17:45:03 smtp postfix/qmgr [ 15636 ] : 1CEAB1002B7E: from = < root@smtp. test .hdomain > , size = 317 , nrcpt = 1 ( queue active ) Aug 10 17:45:03 smtp postfix/smtp [ 15679 ] : 1CEAB1002B7E: to = < ryskw@xxxxxxxxxxxx.hdomain > , relay =xxxxxxxxxxxx.hdomain [ 172 . 20 . 100 . 114 ] :25, delay = 91 , delays = 90 / 0 . 03 / 0 . 21 / 0 . 17 , dsn = 2 . 0 . 0 , status= sent ( 250 2 . 0 . 0 Ok: queued as 71384C0045 ) Aug 10 17:45:03 smtp postfix/qmgr [ 15636 ] : 1CEAB1002B7E: removed 無事送信できていることが確認できました! ちなみに、メールを受信したサーバ側で確認すると、以下のようにメールが表示されました。 Return-Path: < root@smtp. test .hdomain > X-Original-To: ryskw@xxxxxxxxxxxx.hdomain Delivered-To: ryskw@xxxxxxxxxxxx.hdomain Received: from smtp. test .hdomain ( unknown [ 172 . 20 . 100 . 104 ] ) ( using TLSv1. 2 with cipher ADH-AES256-GCM-SHA384 ( 256 / 256 bits )) ( No client certificate requested ) by xxxxxxxxxxxx.hdomain ( Postfix ) with ESMTPS id 71384C0045 for < ryskw@xxxxxxxxxxxx.hdomain >; Wed, 10 Aug 2022 17:45:06 + 0900 ( JST ) Received: by smtp. test .hdomain ( Postfix, from userid 0 ) id 1CEAB1002B7E ; Wed, 10 Aug 2022 17:45:03 + 0900 ( JST ) From:ryskw@smtp. test .hdomain To:ryskw@xxxxxxxxxxxx.hdomain Subject:Postfix test Message-Id: < 20220810084503 .1CEAB1002B7E@smtp. test .hdomain > Date: Wed, 10 Aug 2022 17:43:32 + 0900 ( JST ) test ※送り先のサーバについては諸事情あって xxxxxxxxxxxx.hdomain とホスト名を伏せさせていただきました。 ちゃんと送信元サーバで入力した内容が送られてきています。 これで、 Postfix をインストールした環境でメールが送信できることが確認できました! おまけ Fromアドレスと エンベロープ From sendmail コマンドでメールを送信した際に指定したFromアドレスが ryskw@smtp.test.hdomain にも関わらず、maillog内や受信したメールのヘッダー内にあるReturn-Pathには root@smtp.test.hdomain とあります。 これは Postfix を利用してメールを送信したとき、送信元のサーバではrootユーザで作業したからなのですが、メール内のFromアドレスには ryskw@smtp.test.hdomain と、コマンドで指定したものが入力されています。 メールに表示されているFromアドレス(ヘッダFrom)と異なっていますが、こちらは エンベロープ Fromと呼ばれるアドレスとの違いになります。 この違いはしばしば、封筒に書かれた差出人や住所の情報( エンベロープ From)と、封筒内の便箋に書かれた差出人の名前の違いに例えられます。 詳細は割愛しますが、メール送信時にチェックされるのはこの エンベロープ Fromのみであり、Fromアドレスのほうはチェックされません。 にも関わらず、メールを受信したときに送信元として表示されるのはこのFromアドレスの方なので、実際の送り主とは異なる人がなりすますこともできてしまう、という問題点があります。 そのため、メールを受信した場合にはなりすましに注意しましょう、ということがよく言われます。 メール受信には Dovecot ここまで Postfix を使用してメールを送信する環境を構築してきましたが、メールを受信する環境については別のサーバを構築していました。 また、そちらのサーバではメール送信用の Postfix と併せて、メールを受信するための機能を持つ Dovecot (ダヴコット)というソフトウェアをインストールして構築しました。 機会があれば Dovecot のインストールについてもいずれ記事を作ることができれば、と思います。 最後に いかがだったでしょうか。 Postfix を使用すれば簡単にメールサーバができるんじゃないかと思います。 認証などの機能についても導入することができるため、より安全なメールサーバを自力で構築することも可能ですので、是非お試しください。 それでは、ご覧いただきありがとうございました。 参考 Postfix公式ホームページ エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
はじめに はじめまして、disk-bugと申します。 今回は、 k8s 初心者な私が開発環境にkindを利用して k8s クラスタ を構築し、その クラスタ 上でArgoWorkflowsを動かすことができましたので、 k8s 上にArgoWorkflowsが構築できるまでのお話をしたいと思います。 目次 はじめに 目次 k8sとは? kindとは? ArgoWorkflowsとは? kindを使ってk8sクラスタを構築してみる シングルノードクラスタ作成 マルチノードクラスタ作成 アプリケーションをデプロイしてみる アプリケーションをスケールする アプリケーションに外部から接続する(NodePort Service) アプリケーションに外部から接続する(Ingress) ArgoWorkflowsの導入 まとめ k8s とは? Kubernetes ( k8s )は、デプロイやスケーリングを自動化したり、コンテナ化されたアプリケーションを管理したりするための、 オープンソース のシステムです。 Kubernetes を利用することで、手動デプロイを無くし、高負荷状態になった時のスケーリングやヘルスチェックによる自動復旧などができるようになります。 そもそも Kubernetes の読み方についてですが、 「クバネティス」「クバネテス」「クーベネティス」、色々と読み方があるようです。 他にも k8s やkubeとも呼ばれていますが、本記事では k8s (ケーエイツ、ケーハチ エス )と以下呼ぶようにします。 なぜ k8s なのかというと、 K+8文字+s だからなんだそうです。 kindとは? k8s が便利そうなのはわかったけど、実際どんな感じか動かしてみたいですよね。 k8s の公式ドキュメントに 各種ツールが紹介されており 、ローカル上で実行するツールも紹介されています。 Minikube と kind が紹介されていますが、kindの説明に 1種類のコンテナランタイム上で動作 との記載があり軽量に動かせそうなのかなと思いました。 よって、今回はkindを選択しました。 kindの公式ドキュメントの説明でも、 Dockerコンテナのノードを利用して、ローカル上で k8s クラスタ を実行するためのツールになります。 と紹介されているのでDocker上で k8s クラスタ が構築できるようです。 ArgoWorkflowsとは? k8s 上で何か動かしたいですよね。 もともとチーム内で新しいPipelineツールの検討を行っていたので、 k8s 上で動かせるArgoWorkflowsに目をつけました。 ArgoWorkflows とは、 k8s でジョブを調整するための OSS のコンテナーネイティブワークフローエンジンです。 Argoと聞くと ArgoCD を思い浮かべる方が多いと思いますが、ワークフローエンジンも提供しています。 今までPipelineやJobを実行するツールと言えばJenkinsくらいしか使ってこなかったので、 k8s に加えてArgoWorkflowsという新しい技術への挑戦となりました。 kindを使って k8s クラスタ を構築してみる では実際にkindを使って、 k8s クラスタ を構築してみます。 kindの QuickStart を参照して、まずは自身の端末に kind コマンドをインストールします。 MacOS を使っていますので、以下コマンドでインストールしました。 $ brew install kind $ kind --version kind version 0 . 14 . 0 シング ルノー ド クラスタ 作成 kind コマンドがインストールできましたので、 k8s クラスタ を構築してみます。 以下コマンドで k8s クラスタ が構築できるようですが、エラーが発生しました。 $ kind create cluster ERROR: failed to create cluster: failed to list nodes: command " docker ps -a --filter label=io.x-k8s.kind.cluster=kind --format '{{.Names}}' " failed with error: exit status 1 Command Output: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running? 初歩的なミス・・・Dockerを起動してませんでした。 DockerDesktopを起動して、再度コマンド実行します。 $ kind create cluster Creating cluster " kind " ... ... Set kubectl context to " kind-kind " k8s クラスタ が構築できたので確認します。 $ kind get clusters kind kind という k8s クラスタ が作成されました。 k8s クラスタ を制御できる kubectl というコマンドがあるので、インストールして作成した k8s クラスタ を確認してみましょう。 $ brew install kubectl ... $ kubectl cluster-info --context kind-kind Kubernetes control plane is running at ... ... kubectl コマンドで k8s クラスタ が確認できました。 ここで、今更ながら k8s クラスタ とは何でしょうか? k8s クラスタ とは、コンテナ化されたアプリケーションを実行するためのサーバー群のことです。 そしてサーバー( VM や物理的なマシン)のことをノードと呼びます。 ノードは以下2種類です。 ワーカーノード:コンテナ化されたアプリケーションを実行する環境 マスターノード:コンテナ化されたアプリケーション環境を管理する環境 何を管理するのかというと、 目的の状態になっているのか? 具体的にはアプリケーションが生きているか? 必要なアプリケーション数になっているか? などなど、現在の状態から目的の状態になるように管理します。 kindで構築した k8s クラスタ のノードを確認してみましょう。 $ kubectl get node NAME STATUS ROLES AGE VERSION kind-control-plane Ready control-plane 5m6s v1. 24 . 0 $ kubectl describe node kind-control-plane Name: kind-control-plane ... $ docker container ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 118df6a43f45 kindest/node:v1. 24 . 0 " /usr/local/bin/entr… " About a minute ago Up About a minute 127 . 0 . 0 .1:54251- > 6443 /tcp kind-control-plane 今回はマスターノードだけが構築されたので、シング ルノー ド クラスタ が構築されました。 (1つのノードだけなのでシングル クラスタ 、そのままですね) kindはコンテナをノードとして扱うツールですので、 docker コマンドでもノードの確認が可能です。 一旦、 k8s クラスタ をお掃除します。 $ kind delete cluster マルチノード クラスタ 作成 マスターノードだけのシング ルノー ド クラスタ が構築できたので、次はワーカーノードもあるマルチノード クラスタ を構築しましょう。 (複数のノードがあるからマルチノード、単純ですね) ドキュメントを参照するとymlファイルを使って構築できそうです。 以下の内容でymlファイルを作成し、 kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane - role: worker - role: worker kind コマンドにて先程のymlファイルを指定し、 k8s クラスタ を構築します。 $ kind create cluster --config cluster.yml Creating cluster " kind " ... ... Set kubectl context to " kind-kind " $ kubectl get nodes -o wide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME kind-control-plane Ready control-plane 34s v1. 24 . 0 172 . 24 . 0 . 4 < none > Ubuntu 21 . 10 5 . 10 .104-linuxkit containerd:// 1 . 6 . 4 kind-worker Ready < none > 11s v1. 24 . 0 172 . 24 . 0 . 3 < none > Ubuntu 21 . 10 5 . 10 .104-linuxkit containerd:// 1 . 6 . 4 kind-worker2 Ready < none > 11s v1. 24 . 0 172 . 24 . 0 . 2 < none > Ubuntu 21 . 10 5 . 10 .104-linuxkit containerd:// 1 . 6 . 4 $ docker container ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b101e316a8ff kindest/node:v1. 24 . 0 " /usr/local/bin/entr… " About a minute ago Up 55 seconds 127 . 0 . 0 .1:54512- > 6443 /tcp kind-control-plane 7e18515677be kindest/node:v1. 24 . 0 " /usr/local/bin/entr… " About a minute ago Up 55 seconds kind-worker2 913b69d58e62 kindest/node:v1. 24 . 0 " /usr/local/bin/entr… " About a minute ago Up 55 seconds kind-worker kubectl コマンド・ docker コマンド、それぞれでマスターノード1つとワーカーノード2つが作成されていることが確認できました。 ( Ubuntu が動いているみたいですね) アプリケーションをデプロイしてみる アプリケーションの実行環境であるワーカーノードができたので、実際にアプリケーションをワーカーノード上で動かしてみましょう。 k8s クラスタ 上のワーカーノードにアプリケーションをデプロイするには、Podを作成してデプロイします。 Podとは、 k8s オブジェクトモデルであり、実行できるアプリケーションの単位で、作成またはデプロイする最小かつ最も単純な単位になります。 今回は理解を単純にするために、1Pod1コンテナでPodを作成します。 では、Podを作成してデプロイするため、Podをymlで定義してみましょう。 apiVersion: v1 kind: Pod metadata: name: hoge-pod labels: component: hoge-nginx spec: containers: - name: nginx image: nginx:latest spec にて何のDockerイメージを取得するのか、定義しています。 (今回はnginxのlatest) Podをデプロイしてみましょう。 $ kubectl apply -f hoge-pod.yml hoge-pod created $ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES hoge-pod 1 / 1 Running 0 13s 10 . 244 . 1 . 5 kind-worker < none > < none > ステータスがRunnningとなっていれば、正常に作成されアプリケーションが稼働している状態です。 もしRunningになっていない場合は、以下コマンドで詳細が確認できます。 $ kubectl describe pods hoge-pod ... Events にエラー内容が記載されているので、そこを確認しましょう。 次に問題なくnginxが動いているのか、Podに入って確認します。 $ kubectl exec -it hoge-pod -- bash root@hoge-pod:/# curl -v localhost:80 HTTP/ 1 . 1 200 OK ... localhost:80 に curl すると、nginxのWelcomeページが返却されます。 なぜわざわざPodに入って確認したのかというと、Podは k8s クラスタ の内部に閉じているためです。 外部に公開する方法については、後項で紹介いたします。 一旦、 k8s クラスタ のPodをお掃除します。 $ kubectl delete pod hoge-pod アプリケーションをスケールする 前項では手動でPodをデプロイしましたが、同じ状態のPodを1つ2つと増やすにはどうしたら良いのでしょうか? k8s には、ReplicaSetとDeploymentという機能があります。 ReplicaSetは、設定したレプリカ数分のPodを利用可能な状態で維持してくれる機能になります。 Deploymentは、ReplicaSetの上位レベルの概念でPodのローリングアップデート機能を提供しています。 Podをスケールするために、Deplymentをymlで定義してみましょう。 apiVersion: apps/v1 kind: Deployment metadata: name: hoge-deployment labels: component: hoge-nginx spec: replicas: 3 selector: matchLabels: component: hoge-nginx template: metadata: labels: component: hoge-nginx spec: containers: - name: nginx image: nginx:latest ports: - containerPort: 80 replicas でPodの数、 selector で管理するPodのラベルを定義しています。 なお、Podのラベルは templace.metadata.labels に定義されているものになります。 template で作成するPodを定義しています。 Deploymentを適用してみましょう。 $ kubectl apply -f hoge-deployment.yml deployment.apps/hoge-deployment created $ kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE hoge-deployment 3 / 3 3 3 37s $ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES hoge-deployment-664bf7b75-2zvfm 1 / 1 Running 0 7s 10 . 244 . 2 . 7 kind-worker2 < none > < none > hoge-deployment-664bf7b75-4fdw8 1 / 1 Running 0 7s 10 . 244 . 1 . 6 kind-worker < none > < none > hoge-deployment-664bf7b75-5k8s7 1 / 1 Running 0 7s 10 . 244 . 1 . 7 kind-worker < none > < none > Deploymentを適用すると、 replicas で指定された数のPodが作成されます。 試しにPodを1つ削除してみましょう。 $ kubectl delete pods hoge-deployment-664bf7b75-2zvfm pod " hoge-deployment-664bf7b75-2zvfm " deleted $ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES hoge-deployment-664bf7b75-4fdw8 1 / 1 Running 0 88s 10 . 244 . 1 . 6 kind-worker < none > < none > hoge-deployment-664bf7b75-5k8s7 1 / 1 Running 0 88s 10 . 244 . 1 . 7 kind-worker < none > < none > hoge-deployment-664bf7b75-vgb9k 1 / 1 Running 0 19s 10 . 244 . 2 . 8 kind-worker2 < none > < none > 1つ削除しましたが、Podを確認すると3つになっています。 AGE から見るに1番下のPodが新規に作成されたようです。便利ですね。 これでアプリケーションのスケールアウト・スケールインが可能となりました。 一旦、 k8s クラスタ をお掃除します。 $ kind delete cluster アプリケーションに外部から接続する(NodePort Service) 前項にてDeploymentでPodを複数作成しましたが、 IPアドレス が動的なことにお気づきでしょうか?。 # 1Pod削除前 $ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES hoge-deployment-664bf7b75-2zvfm 1 / 1 Running 0 7s 10 . 244 . 2 . 7 kind-worker2 < none > < none > hoge-deployment-664bf7b75-4fdw8 1 / 1 Running 0 7s 10 . 244 . 1 . 6 kind-worker < none > < none > hoge-deployment-664bf7b75-5k8s7 1 / 1 Running 0 7s 10 . 244 . 1 . 7 kind-worker < none > < none > # 1Pod削除後 $ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES hoge-deployment-664bf7b75-4fdw8 1 / 1 Running 0 88s 10 . 244 . 1 . 6 kind-worker < none > < none > hoge-deployment-664bf7b75-5k8s7 1 / 1 Running 0 88s 10 . 244 . 1 . 7 kind-worker < none > < none > hoge-deployment-664bf7b75-vgb9k 1 / 1 Running 0 19s 10 . 244 . 2 . 8 kind-worker2 < none > < none > 新しく作成されたPodの IPアドレス が、削除されたPodとは異なる IPアドレス が設定されています。 ( 10.244.2.7 から 10.244.2.8 に) k8s クラスタ は動的な環境となっています。 例えば IPアドレス 指定でPodにアクセスしていると、バージョンアップ等でPodが再作成された場合にアクセスできなくなってしまいます。 また、 IPアドレス 指定でのアクセスですと、1つのPodにしかアクセスされず負荷分散ができていません。 そこで登場するのがServiceになります。 Serviceは、Podの集合で実行されているアプリケーションをネットワークサービスとして公開してくれる機能です。 特定のラベルを持ったPodのどれかにアクセスできるようエンドポイントを提供してくれます。 Podにアクセスできるようにするために、Serviceをymlで定義してみましょう。 apiVersion: v1 kind: Service metadata: name: hoge-service spec: type: NodePort selector: component: hoge-nginx ports: - protocol: TCP port: 80 targetPort: 80 nodePort: 30080 今回は NodePort タイプのServiceを定義しています。 NodePort タイプにすることで、ノードの対象ポートへの通信をServiceへ転送するようになります。 selector でPodのラベルを指定しPodの集合体を形成し、 port はServiceのポートになります。 また、 targetPort はPodが待ち受けているポート、 nodePort はノードからSerivceへ通信を転送するポートになります。 Serviceにアクセスできるように k8s クラスタ を構築し直します。 新しい k8s クラスタ をymlで定義します。 kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane - role: worker extraPortMappings: - containerPort: 30080 hostPort: 30080 protocol: TCP ワーカーノードのポート:30080と自端末のポート:30080を紐付けています。 k8s クラスタ を作成しましょう。 $ kind create cluster --config cluster.yml ... $ docker container ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e8c8938d96a7 kindest/node:v1. 24 . 0 " /usr/local/bin/entr… " 2 minutes ago Up 2 minutes 0 . 0 . 0 .0:30080- > 30080 /tcp kind-worker c901092d5858 kindest/node:v1. 24 . 0 " /usr/local/bin/entr… " 2 minutes ago Up 2 minutes 127 . 0 . 0 .1:58099- > 6443 /tcp kind-control-plane ワーカーノードのポート:30080と自端末のポート:30080が紐付けられています。 k8s クラスタ ができたので、DeploymentとServiceを適用しましょう。 $ kubectl apply -f hoge-deployment.yml deployment.apps/hoge-deployment created $ kubectl apply -f hoge-service.yml service/hoge-service created $ kubectl get pods,deployments,services -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/hoge-deployment-664bf7b75-scclb 1 / 1 Running 0 6m47s 10 . 244 . 1 . 3 kind-worker < none > < none > pod/hoge-deployment-664bf7b75-x4gzc 1 / 1 Running 0 6m47s 10 . 244 . 1 . 2 kind-worker < none > < none > pod/hoge-deployment-664bf7b75-xdm4j 1 / 1 Running 0 6m47s 10 . 244 . 1 . 4 kind-worker < none > < none > NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR deployment.apps/hoge-deployment 3 / 3 3 3 6m47s nginx nginx:latest component =hoge-nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT ( S ) AGE SELECTOR service/hoge-service NodePort 10 . 96 . 122 . 115 < none > 80:30080/TCP 6s component =hoge-nginx service/kubernetes ClusterIP 10 . 96 . 0 . 1 < none > 443 /TCP 11m < none > 全て正常に動いていることが確認できたら、自端末から curl もしくはブラウザで localhost:30080 にアクセスしてみましょう。 $ curl -i localhost:30080 HTTP/ 1 . 1 200 OK ... Serviceの selector に誤りがなければ、nginxのWelcomeページが返却されます。 これで、 k8s クラスタ 内のアプリケーションにアクセスできるようになりました。 一旦、 k8s クラスタ をお掃除します。 $ kind delete cluster アプリケーションに外部から接続する( Ingress ) マイクロサービス化に伴い、URLのパスによって異なるアプリケーションを参照したいとなった場合はどうすればよいでしょうか? Ingress が解決してくれます。 Ingress とは、 k8s クラスタ 内のServiceに対する外部からのアクセスを管理する API オブジェクトです。 hoge.example.com/hoge へのリク エス トは、 hoge アプリがデプロイされているPod群の hoge-service へ hoge.example.com/fuga へのリク エス トは、 fuga アプリがデプロイされているPod群の fuga-service へ Ingress がルーティングしてくれます。 ルーティングするために、 Ingress をymlで定義してみましょう。 apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: hoge-fuga-ingress spec: ingressClassName: nginx rules: - http: paths: - pathType: Prefix path: "/" backend: service: name: nginx-service port: number: 80 - pathType: Prefix path: "/hoge" backend: service: name: hoge-service port: number: 80 - pathType: Prefix path: "/fuga" backend: service: name: fuga-service port: number: 80 localhost にアクセスすると、 nginx-service へ localhost/hoge にアクセスすると、 hoge-service へ localhost/fuga にアクセスすると、 fuga-service へ それぞれルーティングする定義となります。 3アプリケーションのDeploymentの定義は以下になります。 apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: component: nginx spec: replicas: 3 selector: matchLabels: component: nginx template: metadata: labels: component: nginx spec: containers: - name: nginx image: nginx:latest ports: - containerPort: 80 --- apiVersion: apps/v1 kind: Deployment metadata: name: hoge-deployment labels: component: hoge-echo spec: replicas: 3 selector: matchLabels: component: hoge-echo template: metadata: labels: component: hoge-echo spec: containers: - name: nginx image: hashicorp/http-echo:latest args: - "-text=hoge" ports: - containerPort: 5678 --- apiVersion: apps/v1 kind: Deployment metadata: name: fuga-deployment labels: component: fuga-echo spec: replicas: 3 selector: matchLabels: component: fuga-echo template: metadata: labels: component: fuga-echo spec: containers: - name: nginx image: hashicorp/http-echo:latest args: - "-text=fuga" ports: - containerPort: 5678 3アプリケーションのServiceの定義は、以下になります。 apiVersion: v1 kind: Service metadata: name: nginx-service spec: selector: component: nginx ports: - protocol: TCP port: 80 targetPort: 80 --- apiVersion: v1 kind: Service metadata: name: hoge-service spec: selector: component: hoge-echo ports: - protocol: TCP port: 80 targetPort: 5678 --- apiVersion: v1 kind: Service metadata: name: fuga-service spec: selector: component: fuga-echo ports: - protocol: TCP port: 80 targetPort: 5678 kindで Ingress を利用するにあたって、 k8s クラスタ を定義したymlを修正します。 kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane kubeadmConfigPatches: - | kind: InitConfiguration nodeRegistration: kubeletExtraArgs: node-labels: "ingress-ready=true" extraPortMappings: - containerPort: 80 hostPort: 80 protocol: TCP 上記定義はkindの ドキュメント に記載されているものを利用しています。 k8s クラスタ を構築し、Deployment・Service・ Ingress を適用しましょう。 $ kind create cluster --config cluster.yml Creating cluster "kind" ... Set kubectl context to "kind-kind" $ kubectl apply -f hoge-fuga-deployment.yml deployment.apps/nginx-deployment created deployment.apps/hoge-deployment created deployment.apps/fuga-deployment created $ kubectl apply -f service/hoge-fuga-service.yml service/nginx-service created service/hoge-service created service/fuga-service created $ kubectl apply -f ingress/hoge-fuga-ingress.yml ingress.networking.k8s.io/hoge-fuga-ingress created $ kubectl get pods,deployments,services,ingress -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/fuga-deployment-65bf9f9c78-kngtk 1/1 Running 0 104s 10.244.0.9 kind-control-plane <none> <none> pod/fuga-deployment-65bf9f9c78-nmv2g 1/1 Running 0 104s 10.244.0.12 kind-control-plane <none> <none> pod/fuga-deployment-65bf9f9c78-wmqwr 1/1 Running 0 104s 10.244.0.11 kind-control-plane <none> <none> pod/hoge-deployment-7df96b5f86-84kpt 1/1 Running 0 104s 10.244.0.10 kind-control-plane <none> <none> pod/hoge-deployment-7df96b5f86-8l5fr 1/1 Running 0 104s 10.244.0.13 kind-control-plane <none> <none> pod/hoge-deployment-7df96b5f86-t9dpd 1/1 Running 0 104s 10.244.0.6 kind-control-plane <none> <none> pod/nginx-deployment-f78754554-7hkmw 1/1 Running 0 104s 10.244.0.7 kind-control-plane <none> <none> pod/nginx-deployment-f78754554-dmnc4 1/1 Running 0 104s 10.244.0.5 kind-control-plane <none> <none> pod/nginx-deployment-f78754554-rw2lb 1/1 Running 0 104s 10.244.0.8 kind-control-plane <none> <none> NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR deployment.apps/fuga-deployment 3/3 3 3 104s nginx hashicorp/http-echo:latest component=fuga-echo deployment.apps/hoge-deployment 3/3 3 3 104s nginx hashicorp/http-echo:latest component=hoge-echo deployment.apps/nginx-deployment 3/3 3 3 104s nginx nginx:latest component=nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR service/fuga-service ClusterIP 10.96.94.98 <none> 80/TCP 72s component=fuga-echo service/hoge-service ClusterIP 10.96.24.225 <none> 80/TCP 72s component=hoge-echo service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4m58s <none> service/nginx-service ClusterIP 10.96.128.45 <none> 80/TCP 72s component=nginx NAME CLASS HOSTS ADDRESS PORTS AGE ingress.networking.k8s.io/hoge-fuga-ingress nginx * 80 41s Ingress は作成するのみでは利用できず、IngressControllerが必要となります。 今回は NGINX IngressController を利用します。 kindの ドキュメント で紹介されている手順で導入します。 $ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml ... $ kubectl wait --namespace ingress-nginx \ --for=condition=ready pod \ --selector=app.kubernetes.io/component=controller \ --timeout=90s pod/ingress-nginx-controller-86b6d5756c-s2sn4 condition met $ kubectl get pods -o wide -n ingress-nginx NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES ingress-nginx-admission-create-jjqjf 0 / 1 Completed 0 2m6s 10 . 244 . 0 . 15 kind-control-plane < none > < none > ingress-nginx-admission-patch-9wzgg 0 / 1 Completed 0 2m6s 10 . 244 . 0 . 14 kind-control-plane < none > < none > ingress-nginx-controller-86b6d5756c-s2sn4 1 / 1 Running 0 2m6s 10 . 244 . 0 . 16 kind-control-plane < none > < none > ingress-nginx-controller がRunningとなっていれば、正常に稼働しています。 全て正常に動いていることが確認できたら、自端末から curl もしくはブラウザで localhost ・ localhost/hoge ・ localhost/fuga にアクセスしてみましょう。 $ curl -i localhost ... < h 1> Welcome to nginx! < /h 1> ... $ curl -i localhost/hoge ... hoge $ curl -i localhost/fuga ... fuga URLのパスによって、異なるアプリケーションが呼ばれていることが確認できました。 ここまでやると何となくですが、 k8s の雰囲気が掴めたかなと思います。 アカウントや認証周りについてはまだまだ勉強中なので、今回は割愛します。 一旦、 k8s クラスタ をお掃除します。 $ kind delete cluster ArgoWorkflowsの導入 ArgoWorkflowsの導入です。 ArgoWorkflows のクイックスタートを参照すると、ポート フォワ ードでの手順となっています。 せっかく Ingress が使えるようになったので、今回は Ingress 経由でArgoWorkflowsを覗けるようにしてみましょう。 まずは、 k8s クラスタ ーの構築です。 Ingress を利用するので前項のymlを利用します。 $ kind create cluster --config cluster.yml Creating cluster " kind " ... Set kubectl context to " kind-kind " k8s クラスタ が構築できたので、ArgoWorkflowsを導入します。 まずは、ArgoWorkflows用にNamespaceを作成します。 Namespaceは、 k8s クラスタ ーリソースを分割する方法であり、プロジェクト毎に パーティション を切るようなイメージです。 $ kubectl create namespace argo $ kubectl get namespace NAME STATUS AGE argo Active 150m default Active 178m ingress-nginx Active 147m kube-node-lease Active 179m kube-public Active 179m kube-system Active 179m local-path-storage Active 178m Namepspaceを明示しなかった場合は、基本的に default が利用されます。 ArgoWorkflowsのインストールですが、 k8s のControllerとして動かしたいので、リリースノート( v3.3.8 )から以下コマンドでインストールします。 $ kubectl apply -n argo -f https://github.com/argoproj/argo-workflows/releases/download/v3. 3 . 8 /install.yaml ArgoWorkflowsの Ingress を、ymlで定義してみましょう。 apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: argo-server-ingress namespace: argo spec: ingressClassName: nginx rules: - http: paths: - pathType: Prefix path: / backend: service: name: argo-server port: number: 2746 公式ドキュメント を参照すると色々書いてありますが、今回は簡単な定義にしています。 Ingress を適用しましょう。 $ kubectl apply -f argo-ingress.yml ingress.networking.k8s.io/argo-server-ingress created Ingress を定義しただけではまだ利用できないので、前項でも利用したNGINX IngressControllerを導入します。 $ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml ... $ kubectl wait --namespace ingress-nginx \ --for=condition=ready pod \ --selector=app.kubernetes.io/component=controller \ --timeout=90s pod/ingress-nginx-controller-86b6d5756c-s2sn4 condition met ArgoWorkflowsの導入はできたのですが、ArgoWorkflowsは HTTPS で待ち受ける設定となっています。 今回は Ingress 配下にArgoWorkflowsを構築しているので、HTTPで待ち受ける設定に変更します。 $ kubectl edit deployment/argo-server --namespace=argo # 1. vim(デフォルトエディタ)が起動されるので、 # template.spec.containers.argsに2項目(--secure, --auth-mode)を追加 spec: containers: - args: - server - --secure=false # HTTPでの通信に変更 - --auth-mode=server # ArgoWorkflowsを動かしたいだけなので認証なしモード # 2. HTTPSと定義されている部分をHTTPで一括置換(vim) : %s/HTTPS/HTTP/g # 3. 保存 : wq deployment.apps/argo-server edited 変更を保存すると変更内容が反映されます。 それではブラウザでアクセスしてみましょう。 open http://localhost ArgoWorkflowsの画面が表示されれば成功です。 試しにワークフローを動かしてみましょう。 まずは、WorkflowTemplateの作成です。 左メニューの Workflow Template -> CREATE NEW WORKFLOW TEMPLATE -> CREATE これでテンプレのワークフローが作成されます。 作成されたワークフローの SUBMIT を押下し、パラメータ設定画面の SUBMIT を押下します。 ワークフロー実行画面に遷移し、少し待つと成功します。 まとめ 以上、kindを使って k8s の雰囲気を掴みながら、ArgoWorkflowsの構築までできました。 k8s 初心者からほんの少しわかるくらいにはなれたのではないでしょうか。 本記事が k8s 理解の一助となれたら幸いです。 最後までお読みいただきありがとうございました。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
まえがき WAFについて(概要) WAFとFirewall(ファイアウォール)とは異なる点 WAFとIPS/IDSとは異なる点 WAFの効果 実害がある場合(攻撃を受けた状態) 実害はない場合(脆弱性が発見された場合など) WAFで対応可能な攻撃の種類 WAFの種類 クラウド型WAFを触ってみた 思わぬ落とし穴 ■良かったこと ■悪かったこと まとめ まえがき お初の方は初めまして。 そうでない方はこんにちは。 ラク スでインフラを担当していますru369と申します。 今回は、WAFについて記事にまとめましたのでよろしくお願いします。 WAFについて(概要) WAFとは・・・Web Application Firewall の略称で通称:ワフと呼びます。 Webアプリケーションの 脆弱性 を突いた攻撃への対策のひとつであり、Webサーバの前面に配置して通信を解析し、Webサイトを保護するセキュリティ対策です。 動作としては一般的な ファイアウォール と似ていますが、異なるところはデータの中身をアプリケーション層レベルで解析できるのが特徴です。 ➡ ECサイト などでのオンラインショッピングやゲームといった個人情報やクレジットカード情報など、ユーザーからの入力を受け付けるようなタイプのWebサイトを不正な攻撃から守ってくれます! WAFと似たセキュリティ対策として、 Firewall 、IPS/IDSがありますが、それぞれ用途(防御の箇所)が異なります。 WAFとの違い WAFと Firewall ( ファイアウォール )とは異なる点 Firewall は ネットワーク層 レベルでのセキュリティ対策です。 送信元と 送信先 の情報( IPアドレス やポート番号など)を元に内部ネットワークへのアクセスを制限します。 ポートスキャンなどの外部公開が不要なサービスを狙った通信は制限できますが、 通信の中身までは検査しません。 ➡正常な通信(パケット)を装った攻撃を区別できず対処できません。 WAFとIPS/IDSとは異なる点 IPS(Intrusion Prevention System) 不正侵入防止システムと呼ばれプラットフォームレベルでのセキュリティ対策です。 IDS(Intrusion Detection System) 不正侵入検知システムと呼ばれ、異常な通信を検知する為に使われます。 ➡簡単に言えば、異常な通信を検知するのはIDS、それをさらに防御まで行うのがIPSというイメージです。 IPS/IDSは、種類により様々ですが、 ファイアウォール よりも内側、反対の外側、 DMZ 上といった設置パターンがあります。 Firewall よりも内側に設置する場合は ファイアウォール を補完する形で防御性能をアップさせます。 一方で外側に設置する場合は、ログを取得して攻撃を把握、分析します。 DMZ 上では、 Firewall をすり抜けてきた攻撃を検出・防御します。 このように使い方によりけりではありますが、IPS/IDSは、OSや ミドルウェア の 脆弱性 を突いた攻撃や、ファイル共有サービスへの攻撃など、さまざまな種類の攻撃を検査・防御します。 しかしながら、Webアプリケーションへの攻撃は多種多様に増えているため、IPSでは攻撃を防ぎきれないことがあります。 また、解析のためにネットワークの性能劣化や遅延が起きてネットワークが使えなくなることがあります。 WAFの効果 WAFを導入しておくと、どのようなことに役に立つのかご紹介します。 情報流出等の セキュリティインシデント が発生すると、以下のようなことに遭遇し得ます。 企業の社会的信用の失墜 Webサイトの長期的閉鎖による機会損失 機会損失により売り上げが下がり直接的/関節的な対策のコストが必要 一方でWAFによる対策をしていると、以下のような事態に遭遇した際に即対応することができます。 実害がある場合(攻撃を受けた状態) 攻撃を受けたWebサイトが実害を受けた場合、元の状態に戻すまでに時間がかかってしまう すぐに防御できないため、対策できるまで被害が拡大してしまう恐れ 攻撃を受ける前と同じ状態でサービスを暫定的であっても再開できない 実害はない場合( 脆弱性 が発見された場合など) Webアプリケーションに 脆弱性 が発見されてもすぐにアプリケーションの改修を行うことは難しく、暫定的な緊急措置がとれない Webアプリケーションが複数ある場合は、それぞれに対応が必要なため、すべてに対応するまで時間がかかる WAFで対応可能な攻撃の種類 基本的にWAFは OWASP Top 10(OWASP:The Open Web Application Security Project)に準拠していると思います。 導入製品によって異なる部分もあると思いますが、例として以下のような攻撃に対してWAFは効力を発揮します。 XSS ( クロスサイトスクリプティング )攻撃 OSコマンドインジェクション ディレクト リ・トラバーサル( パストラバーサル ) パスワードリスト攻撃 ブルートフォース アタック DoS / DDoS攻撃 バッファオーバーフロー WAFの種類 主に以下の3種類があります。 OSS のWAFもありますので合わせて紹介です。 アプライアンス 型WAF( ゲートウェイ 型WAF) WAF専用機器を ゲートウェイ に設置して導入します。 既存のネットワークに直列で接続する「インライン型」や、スイッチなどの ミラーリング ポートに接続する「ミラー型」などがあります。 導入にはネットワーク構成を考慮する必要がありますが、保護対象のWebサーバには負荷がかかりません。 クラウド 型WAF(サービス型WAF) ネットワーク設定を一部変更し、インターネットを経由して クラウド サービスを受けることができます。 基本的に運用は クラウド サービス提供者が行うため、チューニングや 脆弱性 対応も自分で行う必要はありません。 また、機器購入等が不要なことから初期費用を抑えることができます。 ソフトウェア型WAF(ホスト型WAF) 保護対象となるWebサーバーにWAFのソフトウェアをインストールし、通信内容を検査します。 保護対象のサーバーに直接インストールするため、ネットワーク環境の構成や他のサーバーなどに影響を与えず導入することが出来ます。 オープンソース のWAF 無料で利用できる オープンソース のWAFもあります。  ・ModSecurity  ・NAXSI  ・WebKnight 余談ですが、「 OSS WAF」で調べてみるとModSecurityが突出している印象です。 クラウド 型WAFを触ってみた 過去にModSecurityを触ったことはありますが、最近 クラウド 側WAFに触る機会がありましたのでそのお話を少しできればと思います。 (なお、WAFそのものよりどちらかというとリバースプロキシサーバの話になります。) ここでの導入イメージは、1台のWebサーバ( Apache )の前段にWAF(リバースプロキシ(nginx))を導入する形です。 導入前の準備 WAFに転送先(実際のアクセス先)のWebサーバの IPアドレス を登録します。 細かいことでいうと SSH 接続や接続方法(HTTP(S)接続)の設定、チューニングなどが後の作業として控えていますが、最低限の導入準備はこれで終わりです。 ※Webサーバの前段にLoadbalancerサーバがあるような構成であれば、Loadbalancerの IPアドレス を登録することになると思います。 導入してみる WAFの導入は、Webサーバに設定している グローバルIPアドレス の DNS レコード(CNAMEレコードやAレコード)にWAFの IPアドレス を登録するのみです。 導入後 導入後はWAFを経由している分、経由していない場合と比較して、アクセスにかかる時間は数ミリ秒伸びました。 Webアクセスには基本的に影響はなく、WAFの検知テストを行ってもきっちり検知されブロックもされました。 思わぬ落とし穴 WAF自体とは少しずれますが、リバースプロキシサーバの運用経験がほとんどなかったことから嵌ってしまった落とし穴がありました。 良かったことと悪かったことに遭遇しました。 ■良かったこと これまでWebサーバが受け付けていたすべてのアクセスを前段のWAFが受けてくれる形になったことで、Webサーバの負荷が減少しました。 WAF側でキャッシュ機能を有効にしていたり、レスポンスの圧縮をしてくれること、クライアントごとの SSL / TLS リク エス トの暗号化と復号化を代わりにやってくれるためと考えられます。 ■悪かったこと ブラウザからWebアクセスをしていると、WAFにて502エラー、504エラーがランダムで発生していることが確認できました。 実際ブラウザ側では稀にエラー画面が表示されることがありました。 504エラー WAFとWebサーバとの タイムアウト 値の関係がWAF < Webサーバとなっていたことが原因でした。 WAF >= Webサーバに タイムアウト 値を直したところ激減(ほぼ0件)になりました。 502エラー 当初難航しました。 なぜなら特定のアクセスに起因するものではない上、WAF、Webサーバ双方のログから調査することができなかったためです。 (ググってもあまり情報がでてこなかったのも辛かったです) この問題を回避するには、WAFとWebサーバのKeepAliveTimeoutの値の関係をWAF < Webサーバにする必要がありました。 (KeepAliveとKeepAliveTimeoutの補足) KeepAliveは、一度 TCP の接続が行われると同じ接続内で複数のリク エス トのやり取りを行うための設定であり、KeepAliveTimeoutで設定した時間内にクライアントから次のリク エス トが送信されてこなくなると TCP 接続を切断します。 導入当初は、WAF > Webサーバの関係でKeepAliveTimeout値が設定されてしまっていました。 クライアント→WAF→Webサーバの流れでアクセスがありますが、 後続の WAF→Webサーバ間 のコネクションが クライアント→WAF間 よりも短い タイムアウト で切断 され、そのタイミングでクライアントから握ったままになっていたコネクションを利用しようとしたときにエラーになることがあるのだと思います。 ➡WAF < Webサーバの関係のことは Amazon のELB関係のページにも記載がありました。 (参考: https://aws.amazon.com/jp/premiumsupport/knowledge-center/apache-backend-elb/ ) WAF < Webサーバの適正なKeepAliveTimeout値は、2倍3倍以上の差にする必要がありますが一概には言えないので、チューニングしてエラーが発生しない分岐点を探っていく必要があります。 なお、KeepAliveTimeoutを0にするとエラーは発生しなくなりますが、 動作が驚くほど遅くなります のでお勧めしません。 (KeepAlive が0(=無効)になっていると、最初に TCP コネクションを確立したあと、リク エス トの送信及びレスポンスの送信が行われ、都度 TCP の接続がいったん切れます。複数のリク エス トを送る場合にはリク エス トの度に TCP の接続を確立する必要がでてきてしまうためと思われます。) まとめ 昨今のセキュリティ事故事情から様々なセキュリティ強化を求められると思います。 WAF導入の話が出てきた際に、(拙くて申し訳ないですが)本ブログが少しでもお役に立てれば幸いです。 ※参考にしたページ https://httpd.apache.org/docs/2.4/ja/mod/core.html#keepalivetimeout http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive_timeout https://kinsta.com/jp/blog/reverse-proxy/ https://aws.amazon.com/jp/premiumsupport/knowledge-center/apache-backend-elb/ https://it-trend.jp/waf/article/poodle https://www.digicert.com/jp/waf/waf-ips-ids https://it-trend.jp/ids-ips/article/difference https://cweb.canon.jp/it-sec/solution/siteguard/waf/ https://www.jbsvc.co.jp/useful/security/what-is-waf.html エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
技術広報の yayawowo です。 皆様、 SQL を日頃お使いでしょうか? 今回は、 「データを追加」する際に欠かせないINSERT文の使い方と、おすすめの書籍をご紹介 します。 INSERT文の使い方を習得いただくため、お手元で実行可能な SQL 文付きで解説します。 是非、実践しながら習得ください! ※本説明では、 PostgreSQL 9.6を利用します。 テーブルの準備 INSERT文をマスターしよう 基本的な使い方 複数レコードを同時INSERT 別テーブルにINSERT おすすめの書籍 INSERT まとめ ◆ 【 SQL 入門】 PostgreSQL 関連記事 ・ 【SQL入門】UPDATE まとめ ・ 【SQL入門】DISTINCT 使い方 ・ RDBMSとDBMSについて【初心者向け】 ・ SQLの基本【まとめ】 ・ 【RDBMS】PostgreSQLインストール・コマンド入門編 テーブルの準備 まず、INSERT文の解説に入る前に今回使うテーブルを作成します。 テーブルの列定義とCREATE文は以下の通りです。 ◆ 列定義 列名 データ型 PK animal _no integer ○ animal_name text animal_breed text skill _no integer skill_name text ◆ SQL 文 --テーブル作成SQL文 CREATE TABLE sample_animal ( animal_no integer primary key, animal_name text, animal_breed text, animal_sex text, skill_no integer , skill_name text ); では、テーブルが完成しましたのでINSERT文の説明に入ります。 INSERT文をマスターしよう 基本的な使い方 INSERT文の基本的な使い方として、テーブルにデータを登録する方法をご説明します。 まず初めに、列名を指定するパターンです。 < 書式:列名指定有パターン > INSERT INTO テーブル名 (列名1, 列名2,....) VALUES (値1, 値2, ...) ; テーブル名:データを登録したいテーブル名を記載する 列名:値を追加したい列名を記載する 値 :追加したい値を記載する では、INSERT文を書いてみましょう! ◆ SQL 文 --SQL文:INSERTの基本(列名指定有) INSERT INTO sample_animal (animal_no, animal_name, animal_breed, animal_sex, skill_no, skill_name) VALUES ( 1 , ' 犬 ' , ' 柴犬 ' , ' 女 ' , 1 , null ); INSERT INTO sample_animal (animal_no, animal_name, animal_breed, animal_sex, skill_no, skill_name) VALUES ( 2 , ' 犬 ' , ' 柴犬 ' , ' 男 ' , 2 , null ); INSERT INTO sample_animal (animal_no, animal_name, animal_breed, animal_sex, skill_no, skill_name) VALUES ( 3 , ' 犬 ' , ' チワワ ' , ' 男 ' , 1 , null ); ◆実行結果 animal _no animal_name animal_breed animal_sex skill _no skill_name 1 犬 柴犬 女 1 (null) 2 犬 柴犬 男 2 (null) 3 犬 チワワ 男 1 (null) なお、上記 SQL 文では列名一つ一つ指定しましたが、省略することもできます。 列名指定をしない場合のINSERT文は、以下の通りです。 < 書式:列名指定無パターン > INSERT INTO テーブル名 VALUES (値1, 値2, ...) ; ※注意点 列名指定をしない場合の「値」は、列名順通りに正しく指定するよう、注意ください! ◆ SQL 文 --SQL文:INSERTの基本(列名指定無) INSERT INTO sample_animal VALUES ( 1 , ' 犬 ' , ' 柴犬 ' , ' 女 ' , 1 , null ); INSERT INTO sample_animal VALUES ( 2 , ' 犬 ' , ' 柴犬 ' , ' 男 ' , 2 , null ); INSERT INTO sample_animal VALUES ( 3 , ' 犬 ' , ' チワワ ' , ' 男 ' , 1 , null ); 実行結果は列名を指定した結果と変わりません。 列名を指定しない場合はとてもシンプル且つ、便利に見えますが、想定していないトラブルが発生するリスクもあります。 列名指定をしないINSERT文を使う際は、ご注意いただきながらご利用ください。 複数レコードを同時INSERT 続いて、複数レコードを1つのINSERT文を使い同時に追加する場合を説明します。 前述したINSERTの基本をご理解いただけていれば、とても簡単な方法です。 < 書式 > INSERT INTO テーブル名 VALUES (値1-1, 値1-2, 値1-3), (値2-1, 値2-2, 値3-3) ... ; では、実際に値を入れてみてみましょう。 ◆ SQL 文 --SQL文:複数レコード同時INSERT INSERT INTO sample_animal VALUES ( 1 , ' 犬 ' , ' 柴犬 ' , ' 女 ' , 1 , null ), ( 2 , ' 犬 ' , ' 柴犬 ' , ' 男 ' , 2 , null ), ( 3 , ' 犬 ' , ' チワワ ' , ' 男 ' , 1 , null ); ◆実行結果 animal _no animal_name animal_breed animal_sex skill _no skill_name 1 犬 柴犬 女 1 (null) 2 犬 柴犬 男 2 (null) 3 犬 チワワ 男 1 (null) VALUESの後に同時INSERTしたい値を指定しているのが、お分かりいただけるのではないでしょうか? INSERT文を1つずつ書くよりも効率的ですね。 別テーブルにINSERT 別テーブルに問い合わせる処理である「副問合せ(サブクエリ)」を使った、INSERT文についてご説明します。 今回利用するテーブルの準備を先にしましょう。 初めに今回SELECT文で呼び出す、sample_animalテーブルのデータを以下の内容でUPDATEします。 skill _no が1の場合:走る skill _no が2の場合:飛ぶ ◆ SQL 文 --SQL文:sample_animalテーブルをUPDATE UPDATE sample_animal SET skill_name = ' 走る ' WHERE skill_no = 1 ; UPDATE sample_animal SET skill_name = ' 飛ぶ ' WHERE skill_no = 2 ; ◆実行結果 animal _no animal_name animal_breed animal_sex skill _no skill_name 1 犬 柴犬 女 1 走る 2 犬 柴犬 男 2 飛ぶ 3 犬 チワワ 男 1 走る 実行結果のようになりましたか? では、次に今回SELECTで呼び出した値を書き出す、sample_skill テーブルをCREATEしてみましょう。 ◆ 列定義 列名 データ型 PK skill _no integer ○ skill_name text ◆ SQL 文 --テーブル作成SQL文 CREATE TABLE sample_skill ( skill_no integer primary key, skill_name text ); ここまで来ましたら準備完了です。 では、sample_animalテーブルからSELECTで呼び出した値を別テーブルである、sample_skill テーブルにINSERTしてみます。 利用する書式は以下の通りです。 < 書式 > INSERT INTO テーブル名1 (列名1, 列名2, .... )   SELECT テーブル名2.列名 FROM テーブル名2 WHERE 条件; SQL 文をたたいてみましょう! ◆ SQL 文 --SQL文:別テーブルにINSERT INSERT INTO sample_skill SELECT sample_animal.skill_no, sample_animal.skill_name FROM sample_animal WHERE animal_no IN ( 1 , 2 ); ◆実行結果 animal _no animal_name animal_breed animal_sex skill _no skill_name 1 犬 柴犬 女 1 走る 2 犬 柴犬 男 2 飛ぶ 3 犬 チワワ 男 1 走る skill _no skill_name      👇 skill _no skill_name 1 走る 2 飛ぶ 上記実行結果の通り、スキルだけを抽出することができました。 INSERT文の使い方の説明は以上となります。 もし、INSERT文だけでなく、CREATE文/ SELECT文/UPDATE文を何も見ずに書ける人は、次ステップである SQL でのパフォーマンスチューニングに挑戦するのもおすすめです! おすすめの書籍 これから SQL を学びたい方に、おすすめの3冊はこちら! ◆ スッキリわかる SQL 入門 第2版 ◆ イラストで理解  SQL  はじめて入門 ◆ SQL 第2版 ゼロからはじめるデータベース操作 (プログラミング学習シリーズ) DB設計やパフォーマンスチューニングを学びたい方に、おすすめの4冊はこちら! ◆ SQL 実践入門──高速でわかりやすいクエリの書き方 ◆ SQL パフォーマンス詳解 ◆ SQL アンチパターン ◆ 達人に学ぶDB設計 徹底指南書 INSERT まとめ いかがでしたでしょうか? 今回は、 SQL 入門としまして『INSERT まとめ』をご紹介させていただきました。 実際にお手元で SQL を動かすことで、より理解を深めることができたのではないでしょうか。 改めまして、本記事がINSERT文を学ぶ方にとって、少しでもお役たてれば幸いです。 最後までお読みいただきありがとうございました! エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
Gitを使って開発する際、最新の ソースコード を取得する場面は多分にあると思います。 本投稿では、 git pull コマンドの基本的な使い方〜主要なオプションの紹介 をすると共に、よく混同されがちな、 fetch と merge との違い についてもまとめさせていただきます。 Gitを使い始めたばかりの方から、 git pull について学び直したいという方まで、開発の際に参考にしていただければ幸いです。 弊社ブログのGitに関わる関連記事もぜひご一読ください! 【超入門】初心者のためのGitとGitHubの使い方 【Git入門】git stashで作業を便利に退避する 【Git入門】git commitを取り消したい、元に戻す方法まとめ 【Git入門】git cloneで既存リポジトリをクローンしよう! 目次 目次 git pullとは? git pullの基本的な使い方 git pullとfetchとmergeの関係性 git pullのオプション紹介 pull時のメッセージを非表示にする ダウンロードコンテンツの詳細を表示する mergeをrebaseに変更する merge時のコミットを実行しない まとめ   git pull とは? git pull とは、 リモー トリポジ トリから最新の状態をローカル リポジトリ に反映するコマンド のことです。 状態と記載した通り、反映される対象は ソースコード 等のファイルだけではなく、履歴やログも含まれます。 複数人で システム開発 をする場合、各々の環境から作業を行うため、他の開発者が実装した内容をローカル リポジトリ に取り込む必要があります。 「作業の初めに必ず git pull を実行する」といったルールを作ることで、リモー トリポジ トリと差分のない状態で開発に着手することができます。 git pull の基本的な使い方 $ git pull 上記コマンドにより、リモー トリポジ トリの状態をローカル リポジトリ に反映することができます。 このように引数無しでコマンドを実行した場合は、作業中のブランチと関連付けられているリモー トリポジ トリのブランチを対象に pull が実行されます。 この関連付けられているブランチのことを アップストリーム(upstream)ブランチ と呼びます。 アップストリームブランチは以下コマンドで確認できます。 $ git branch -vv 実行結果は下記のような出力となります。 $ git branch -vv * main XXXXXXXX(コミット番号) [origin/main] Merge branch 'feature/hogehoge' into 'main' 上記の例ですと、ローカルの main ブランチのアップストリームブランチが origin/main であることが分かります。 また、デフォルトのアップストリーム以外のブランチを指定したい場合は git pull に引数をつけて実行します。 $ git pull <remote> <branch> 実行例は下記のようになります。 $ git pull origin feature/hogehoge アップストリームブランチを明示的に設定する場合は、以下コマンドを実行します。 $ git branch --set-upstream-to=<remote>/<branch> [ローカルブランチ名] git pull と fetch と merge の関係性 git fetch は、 git pull と同じくリモー トリポジ トリから最新の状態をローカルに反映するコマンドなのですが、反映先がアップストリームブランチとなります。 また、 git merge はアップストリームブランチからローカルブランチを更新するコマンドとなります。 つまり、 git fetch と git merge の動作を合わせて行うコマンドが git pull になるのです。 git pull リモートブランチの状態をローカルブランチに反映 git fetch リモートブランチの状態をローカルのアップストリームブランチに反映 git merge アップストリームブランチの状態をローカルブランチに反映 ローカルの作業用ブランチまで 一気通貫 で最新の状態に更新したい場合は git pull で問題ありませんが、コンフリクトが発生する際など順を追って作業したい場合にはコマンドを分割して実行するのがよいでしょう。 git pull のオプション紹介 git pull コマンドには様々なオプションがあります。 オプションは以下コマンドで参照可能です。 $ git help pull コマンドを実行すると、以下のような結果が出力されます。 NAME git-pull - Fetch from and integrate with another repository or a local branch SYNOPSIS git pull [<options>] [<repository> [<refspec>...]] DESCRIPTION Incorporates changes from a remote repository into the current branch. In its default mode, git pull is shorthand for git fetch followed by git merge FETCH_HEAD. More precisely, git pull runs git fetch with the given parameters and calls git merge to merge the retrieved branch heads into the current branch. With --rebase, it runs git rebase instead of git merge. <repository> should be the name of a remote repository as passed to git-fetch(1). <refspec> can name an arbitrary remote ref (for example, the name of a tag) or even a collection of refs with corresponding remote-tracking branches (e.g., refs/heads/*:refs/remotes/origin/*), but usually it is the name of a branch in the remote repository. Default values for <repository> and <branch> are read from the "remote" and "merge" configuration for the current branch as set by git-branch(1) --track. Assume the following history exists and the current branch is "master": A---B---C master on origin / D---E---F---G master ^ origin/master in your repository (中略) OPTIONS -q, --quiet This is passed to both underlying git-fetch to squelch reporting of during transfer, and underlying git-merge to squelch output during merging. -v, --verbose Pass --verbose to git-fetch and git-merge. (後略) コマンドの使い方とオプションに関する説明が詳細に出力されます。 上述の fetch と merge についての説明も記載されています。 本投稿では、このオプション群の中からいくつかを抜粋して紹介させていただきます。 オプション ショートオプション 用途 --quiet -q pull 時のメッセージを非表示にする --verbose -v ダウンロードコンテンツ の詳細を表示する --rebase -r merge を rebase に変更する --no-commit merge 時のコミットを実行しない ※以降の例ではショートオプションをしています。 pull 時のメッセージを非表示にする git pull コマンドはデフォルトで進捗状況が出力されるようになっています。 ( --progress オプションと同様の動きをします。) この進捗状況を非表示にする際には -q オプションを使用します。 $ git pull -q ダウンロードコンテンツ の詳細を表示する $ git pull -v fetch と merge コマンド双方に対してログが詳細に出力されます。 merge を rebase に変更する git pull をオプション無しで実行した場合は git fetch + git merge の動作が 一気通貫 で行われますが、 -r オプションを使用することで rebase の動きに変更することができます。 $ git pull -r rebase は単体ではコミットの修正や複数のコミットを統合したい際に使用するコマンドです。 リモートにpushする前にコミットを綺麗にすることが可能ですが、過去の履歴を変更できてしまうため、複数人で開発している場合に意図的なコミットの改竄が必要でない限りは merge を使うのがよいでしょう。 (チームでルールを決めて使用している場合は全く問題ありません。) merge 時のコミットを実行しない デフォルトで git pull を実行すると新規のコミットが作成されます。 $ git pull --no-commit 上記オプションを使用すると、コミットを作成する直前に処理が中断されるため、コミットを打つ前にマージ内容を確認し、調整することが可能です。 まとめ Git入門ということで、 git pull コマンドの使い方と一部オプションをご紹介しました。 git pull はコマンド単体のオプションの他に、 fetch と merge それぞれに関連するオプションも多数用意されています。 それぞれの動きを理解することでより柔軟にバージョン管理を行うことができ、「コミットを打つ/打たない」や「履歴をそのまま残す/新しく作成する」等の認識合わせにも使用できると思いますので、よろしければ今後の参考になさってください。   エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 https://rakus.hubspotpagebuilder.com/visit_engineer/ rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター