OmniAICreator/Qiita-1.07M huggingface dataset:
【初心者入門】Rustメモリ管理(所有権、借用、ライフタイム)

## メモリ管理

- メモリとはCPUが処理を行う際に読み書きを行うデータを格納する領域。

https://www.youtube.com/watch?v=mngrC0QZyfQ

https://qiita.com/TAKUYA-110/items/e289a07d3333199711a2

- Rustはを採用していない

→プログラマがメモリ管理をコントロールすることができる

→低レベルソフトウェアを開発できる（OSなど）

## ガベージコレクション

- ガベージコレクションとはメモリの解放を自動で行ってくれる機能

https://www.youtube.com/watch?v=oZdu_M4QXuo

- GC(ガベージコレクション)が使用されている言語とされていない言語がある

## 所有権・借用権・ライフタイム

- Rustではガベージコレクション（GC）を使用せずにメモリ安全性を確保するために所有権と借用とライフタイムの仕様を採用している

【**所有権】**

- 所有権：変数の中身を所有する権利
- Rustの所有権（ownership）は、値の所有者をただ一つに限定し、**その所有者が値の破棄処理を行う責任を持つ**という規則である。
- 変数を代入すると、Rustは変数の所有権ごと渡す

```rust
let a = 'hello'
let b = a

/**
エラー
変数aの所有権はbに移動（ムーブ）される→aはもう参照できないためエラー
**/
```

参考動画

https://www.youtube.com/watch?v=vUMBSkr0Y7c

【**借用**】

- 借用とは所有権を移さないで、変数の中身を一定期間レンタルできること
- Rustの変数には2種類ある
    - イミュータブル：データを作成したら変更ができない
    - ミュータブル：データを作成しても変更ができる
- それぞれの借用の方法

    イミュータブルな借用

    ```rust
    let a = 'hello'
    let b = &a

    エラー起きない
    所有権をaに残したまま
    ```

    ミュータブルな借用

    ```rust
    let mut x = vec![1, 2, 3]

    let y = &mut x
    let z = &mut x

    エラー
    ミュータブルな変数の借用は複数できない
    ```

- 借用の注意点

    ミュータブルな借用とイミュータブルの借用は同時にできない

    ```rust
    let mut x = vec[1, 2, 3]

    let y = &mut x
    let z = &x

    エラー
    xは可変として借用されているため、不変として借りることができません
    ```

参考動画

https://www.youtube.com/watch?v=8R8847z15lw

【**ライフタイム**】

- ライフタイム：借用において、所有者のスコープより長く存続できない

```rust
let a
{
	let b = 1
	let a = &b
}
println!{a}

エラー
bはスコープを抜けた時点でメモリを解放する
→aはメモリ解放後のリソースを参照してしまうことになるため
```

参考動画

https://www.youtube.com/watch?v=q2WjxNdSWxU

---

【Rustについての参考動画】

https://www.youtube.com/watch?v=otDi1f_LpOc
phpstorm xdebug どうしてもつながらないよ。そんなとき

だれかの役に立てば

xdebug.log ファイルを見ても明らかに接続成功してるのに、breakpointで止まらない。
そんなときは

Language & Frameworks > PHP > Debug > External connections の

```
Ignore external connections through unregistered server configurations
```

のチェックをはずしてみてください！きっとつながります
KubernetesのIngressをIstioのサービスメッシュ(istio-ingresgateway)に接続する

KubernetesのIngressを入口にして後はIstioのサービスメッシュに任せたい場合に、Ingressとingressgatewayを接続する必要があります。microk8sを使ってこれを実現するのに少し迷ったのでメモとして残します。

## istio-ingressgateway をClusterIPにする

istio-ingressgatewayはデフォルトでLoadBalancerタイプになっていますのでClusterIPに変更します。

```
kubectl -n istio-system edit svc istio-ingressgateway
# type: LoadBalancer になっている部分を type: ClusterIP に変更して保存
```

## Ingressをistio-systemネームスペースにデプロイする

`istio-system`ネームスペースにデプロイして、`istio-ingressgateway`サービスにトラフィックを向けます。
`istio-ingressgateway` はサービスメッシュの入り口となるサービスで、ここから先はサービスメッシュの定義に従って制御されます。

```yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: http-ingress
  namespace: istio-system
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
  rules:
  - http:
      paths:
      - path: /
        backend:
          serviceName: istio-ingressgateway
          servicePort: 80
```

## 参考

 - [エッジからメッシュへ: GKE Ingress を介したサービス メッシュ アプリケーションの公開](https://cloud.google.com/architecture/exposing-service-mesh-apps-through-gke-ingress?hl=ja)
LaravelのAuth機能で表示されるナビバーにリンクを追加したい。

#LogoutしかメニューがないAuth機能のナビバー。

Laravelでポートフォリオを作成中です！！

Auth機能でログイン機能を実装したのち
右上部にログインした後に名前が表示されるのですが
そこのナビバーって
Logoutしかメニューがないんですね。

今回のポートフォリオで
追加で「新規投稿画面」
「ユーザー情報画面」とか他画面に行くためのリンクの追加がしたい。。。。



##日本語で探したかったけどうまく言葉が見つからんやった

なので英語で説明あったので。
[こちら](https://stackoverflow.com/questions/61400144/adding-links-to-laravel-auth-navbar)

まだ初心者なので英語のソース見るのドキドキしちゃうんですが
簡単でした。

>This should be super simple to do, I'm not sure what you're doing but to add additional links you can add an anchor tag to the dropdown div:


スーパーシンプルやで。アナタ様がどのような感じでやったか知らんけど、
a タグを div ん中に追加するんやで。


```
<a class="dropdown-item" href="#">About</a>
```
たとえばこんな感じやな

```
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
    <a class="dropdown-item" href="#">About</a>
    <a class="dropdown-item" href="{{ route('logout') }}" onclick="event.preventDefault(); document.getElementById('logout-form').submit();">
        {{ __('Logout') }}
    </a>                             
    <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;"> 
        @csrf
    </form>
</div>
```

て感じでした。


aタグの中に「dropdown-item」のクラス名を追加して
あとはお好きなようにリンク貼っちゃっていいみたいです。


簡単じゃった。またレベルが上がりました。
logging zap: レベル毎ファイル出力

# Overview
- ログレベル毎にファイル出力する要件がまだある。
- かつ、構造化ログを扱う。
- [`zap`](https://pkg.go.dev/go.uber.org/zap)が柔軟に設定できそうだった。


# Detail

## 設定方法
- 出力ファイルの作成
- `zap core.EncoderConfig`のインスタンス作成
- `zapcore.NewCore(enc Encoder, ws WriteSyncer, enab LevelEnabler) Core`で、レベル別の`core`のインスタンスを作成
- オプションの生成
- `zap.New(core zapcore.Core, options ...Option) *Logger`で`*Logger`のインスタンスを生成

## Sample
`Info`と`Error`を設定。Errorのみ標準エラーとファイルに出力。エラーハンドリングは省略。


```go
package main

import (
	"os"
	"time"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

func main() {
	infoFile, _ := os.OpenFile("/tmp/info.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	errorFile, _ := os.OpenFile("/tmp/error.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	encoderConfig := zapcore.EncoderConfig{
		TimeKey:        "time",
		LevelKey:       "level",
		NameKey:        "name",
		CallerKey:      "caller",
		MessageKey:     "msg",
		StacktraceKey:  "stacktrace",
		EncodeLevel:    zapcore.LowercaseLevelEncoder,
		EncodeTime:     zapcore.ISO8601TimeEncoder,
		EncodeDuration: zapcore.StringDurationEncoder,
		EncodeCaller:   zapcore.ShortCallerEncoder,
	}

	infoCore := zapcore.NewCore(
		zapcore.NewConsoleEncoder(encoderConfig),
		zapcore.AddSync(infoFile),
		zapcore.InfoLevel,
	)
	sy := zapcore.NewMultiWriteSyncer(os.Stderr, errorFile)
	errorCore := zapcore.NewCore(
		zapcore.NewJSONEncoder(encoderConfig),
		sy,
		zapcore.ErrorLevel,
	)

	opts := []zap.Option{}
	opts = append(opts, zap.WrapCore(func(core zapcore.Core) zapcore.Core {
		return zapcore.NewSampler(
			core,
			time.Second,
			100, //Initial
			100, //Thereafter,
		)
	}))
	logger := zap.New(zapcore.NewTee(infoCore, errorCore), opts...)

	logger.Info("test")
	logger.Error("aaaaaaa")
	//	logger.Fatal("oooooo")
}
```

# Reference

https://pkg.go.dev/go.uber.org/zap

https://pkg.go.dev/go.uber.org/zap@v1.17.0/zapcore
【未経験】プログラミング歴４ヶ月でデプロイしたApp

<h2>初めに</h2>
はじめまして、今回初めてQiitaに投稿します、るんるんです。
普段は都内の大学に通う学生ですが、今年の冬にプログラミングの勉強を開始しました。

何かオリジナルのWebアプリケーションを作成したいと思っていた矢先、友人から「*就活に必要な自己分析がなかなか始められない*」との相談をキッカケに*自己分析をサポートする*[freamwork.app](https://freamworkapp.herokuapp.com/)を開発しました。![freamworkapp.headnail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1035524/0b3b588d-4d94-1c48-0f49-07f6993ea8d6.png)

<h2>採用言語・採用理由</h2>
<h3>フロントエンド</h3>
<h4>HTML,CSS（Sass）,jQuery</h4>
→フロントエンドは流行りのVueやReactなどを採用したかったが、技術不足であり今回は断念。
<h3>バックエンド</h3><h4>Ruby</h4>
→デプロイまで最短ルートで進みたかったことから、便利で使いやすいフレームワークRuby on Railsを採用した。
#####<主なgem＞
・chartkick（グラフ作成のため）

<h3>インフラ</h3><h4>デプロイ先</h4>
→Herokuを採用。画像に対して不安を抱えるHerokuだが、写真に関する機能は特にないので良しとした。何よりコスパ最強。

##制作期間
１ヶ月（chartkickの実装に時間がかかった）

##サイトの概要
自己分析をする上で必須級な「フレームワーク」に着目した。
フレームワークを使用する上で陥りがちなのが「自己分析をしても果たしてちゃんとできているかわからない」ことが挙げられる。
そこで、*ヒント機能を設けユーザーが方向性を見失わないように工夫した*。
また*シンプルで直感的な機能性とデザイン性と機能性を意識して、ユーザーの自己分析を始める際のハードルを低くした*。

##こだわった点
・モチベーショングラフをユーザーに合わせてグラフを作るために、パス機能を持たせた。
→chartkick（グラフを作るgem）については全くの初見であったが、とにかく調べまくって実装できた。
・ヒント機能を設けた
→自己分析をやる際にユーザーがベクトルを見失う可能性を危惧したため、そのフレームワークに対するヒント機能を用意した。

##作ってみた感想
開発を始める当初は２ヶ月ぐらいかかる予定であったが、早めに終わった。
デザインのセンスが皆無なので、なんとか努力で向上していきたい。
フロントエンドにjQueryを採用したが、Reactなどのモダンな技術を用いた方が良かった。

##これからの指針
次に開発するものは未定ですが、人気度に高いPythonなどを使用したものを作りたい。
また先述の通りReactを用いたフロントエンドにも挑戦したい。
Dockerを用いた仮想環境で開発をしていきたい。

拙い文章でしたが最後まで読んでくださり、ありがとうございました。
【GCP】Firebaseについて

Firebase という便利な機能があるみたいだが、請求先サブアカウントでは、Sparkプランが使えなかったので、調べてみた。


###関連情報

Firebase 
https://www.fenet.jp/infla/column/network/firebase%E3%81%AE%E6%A9%9F%E8%83%BD%E3%81%A8%E4%BD%BF%E3%81%84%E6%96%B99%E3%81%A4%EF%BD%9C%E3%83%A1%E3%83%AA%E3%83%83%E3%83%88%E3%82%84%E6%96%99%E9%87%91%E3%83%97%E3%83%A9%E3%83%B3%E3%82%82%E7%B4%B9/#Firebase%E3%81%AE%E6%96%99%E9%87%91%E3%83%97%E3%83%A9%E3%83%B33%E3%81%A4

https://qiita.com/qrusadorz/items/843e65a77ce5e7b680a9

実際にプロジェクトをFirebaseで作ってみたらSparkプランは選べなかった
レポートで値引きもされてなかった。
この挙動でいいのかを確認しないといけない

###結果
Sparkプランが使えないのは正常な動きのよう。
商用向けなので、たしかにそうだろう。
でも、サブアカウントを削除するとSparkプランになるみたい。
エクセルVBA 図形(Shape)を操作する。

### 図形の種類
　・VBA上で分類されるエクセルの図形の種類は、ざっと以下の通り。
　・詳細はリンク参照。

　・図形, ActiveX部品, フォーム部品, グラフなど
　　およそ図形っぽいものすべて。

### 参照
```vb
  Worksheets(1).Shapes
  Worksheets(1).Shapes(1)
  Worksheets(1).Shapes("図形1")  
```
　・各図形の参照は、番号か

### すべて参照
```vb
  Dim s As shape
  For Each s In .Shapes
```
### 複製
```vb
  With sp.Duplicate
    .Name = sp.Name & "図形名"
    .Top = sp.Top
    .Left = sp.Left + sp.Width
  End With
```

### コピー & ペースト
```vb
  s.Select
  s.Copy
  sheet.Paste or( Range(XX).Paste)
```
### 座標, サイズ変更
```vb
  ' x, y (絶対座標)
  Selection.ShapeRange.Top = 300
  Selection.ShapeRange.Left = 300

  ' width, height
  Selection.ShapeRange.Width = 300
  Selection.ShapeRange.Height = 300

  ' x, y (相対座標)       
  Selection.ShapeRange.IncrementLeft = 100
  Selection.ShapeRange.IncrementTop = 300

```

# 参考リンク
・基礎的な使い方

https://excel-ubara.com/excelvba5/EXCELVBA278.html


・図形の操作

https://kosapi.com/post-3169/

・図形の種類

https://www.relief.jp/docs/018476.html
【git】暗記できない自分用のgit commandメモ

毎回あのコマンドどう打つんだっけ？ってなるので
メモ用に自分がよく使うgit commandをまとめたものになります。

gitのコマンドちゃんと覚えている人すごい・・・

## サブモジュールを最新に更新する
```
$ git submodule foreach git pull origin master
```

## brunchに登録されているハッシュ値を更新する
```
$ git submodule update --init --recursive
```

## 変更退避
```
$ git stash
```

## 退避したリスト表示
```
$ git stash list
```

## 退避した作業を戻す
```
$ git stash apply stash@{0}
```

## 退避した作業の削除
```
$ git stash drop stash@{0}
```

## add取り消し
```
$ git reset HEAD <ファイル名>
```

## commitの取り消し
```
$ git reset --hard HEAD^
```

## 一部の更新だけを取り込みたい
```
$ git cherry-pick <ハッシュ値>
```

## ローカルブランチお掃除候補表示
```
$ git branch --merged | grep -v 'master\|develop'
```

## ローカルブランチお掃除
```
$ git branch --merged | grep -v 'master\|develop' | xargs -I% git branch -D %
```

## 空のブランチをcommitする
```
git commit --allow-empty -m "empty commit"
```

忘れて検索したものを随時更新していきます。
EMUIバージョンの取得方法

EMUIはファーウェイがAndroidをベースにカスタマイズしたものです。プログラムでは次の方法でEMUIのバージョンを取得できます。

```java
public class EmuiInfo {

    public static EmuiInfo getEMUI() {
        EmuiInfo.Builder builder = new EmuiInfo.Builder();
        try {
            Class<?> classType = Class.forName("android.os.SystemProperties");
            Method getMethod = classType.getDeclaredMethod("get", new Class<?>[]{String.class});
            String buildVersion = (String) getMethod.invoke(classType, new Object[]{"ro.build.version.emui"});
            int startIndex = buildVersion.indexOf("_");
            if (startIndex != 1) {
                String emuiVersion = buildVersion.substring(startIndex + 1);
                String[] versionArray = emuiVersion.split("\\.");
                builder.major(versionArray[0]);
                builder.minor(versionArray[1]);
                builder.patch(versionArray[2]);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return builder.build();
    }

    private String major = "";
    private String minor = "";
    private String patch = "";

    private EmuiInfo(Builder builder) {
        this.major = builder.major;
        this.minor = builder.minor;
        this.patch = builder.patch;
    }

    public String getMajor() {
        return this.major;
    }

    public String getMinor() {
        return this.minor;
    }

    public String getPatch() {
        return this.patch;
    }

    public String toString() {
        return this.major + "." + this.minor + "." + this.patch;
    }

    private static class Builder {
        private String major = "";
        private String minor = "";
        private String patch = "";

        public Builder() {
        }

        public Builder major(String major) {
            this.major = major;
            return this;
        }

        public Builder minor(String minor) {
            this.minor = minor;
            return this;
        }

        public Builder patch(String patch) {
            this.patch = patch;
            return this;
        }

        public EmuiInfo build() {
            return new EmuiInfo(this);
        }
    }
}
```
git リベース/コミット編集/作業の避難



##git リベースで履歴を整えた形で変更を統合する
```
＊注意：Githubにプッシュしたコミットをリベースできない！！！
git push -f　で強制的にプッシュできるが履歴が壊れるので、【絶対NG！！！！】

$ git rebase ブランチ名
```

##git　プルのマージ型
```
$ git pull リモート名　ブランチ名
$ git pull origin master
```

##git プルのリベース型
```
$ git pull --rebase リモート名　ブランチ名
$ git pull --rebase origin master

・デフォルトでリベース型にするには
$　　git config --global pull.rebase true
```

##git　直前のコミットをやり直す
```
*GithubにプッシュしたcommitはNG！！

$ git commit --amend
```

##git 複数のコミットをやり直す
```
$ git rebase -i コミットID　　　　　　//-i interactiveの略
$ git rebase -i HEAD~3　　　　　　//直前のコミット３つをやり直す！何個前のコミットか数字を置く

・下記の３つのコミット情報が出る！
pick gh21f6d ヘッダー修正
pick 93054e 　　ファイル追加
pick 84gha0d READNE修正

・修正したいコミットにeditと修正を行う！その後ファイルの保存をする！
pick gh21f6d ヘッダー修正
pick 93054e 　　ファイル追加
edit 84gha0d READNE修正　　　

・git commit --amendを行うとコミット名を変更できる！
edit 84gha0d READNE修正　　　　//editに変更したコミット

・修正が終われば
＄　　git rebase --continue

$ git logで修正されたか確認すること
```

##git　コミットを並び替える
```
$ git rebase -i HEAD~数字

下記のコミットの順番を変更する際は、書き換えればいいだけ
pick gh21f6d ヘッダー修正
pick 93054e 　　ファイル追加
pick 84gha0d READNE修正
↓
pick 93054e 　　ファイル追加
pick 84gha0d READNE修正
pick gh21f6d ヘッダー修正　　　　その後ファイルを保存で変更される！
```

##git　複数のコミットを１つにまとめる
```
$ git rebase -i HEAD~数字

・まとめたいコミットのpickからsquashに変更する！
pick gh21f6d ヘッダー修正
squash 93054e 　　ファイル追加
squash 84gha0d READNE修正
↓
pick gh21f6d ヘッダー修正　　　全てのコミットがまとめられる！！！
```

##git　コミットの分割を行う！
```
$ git rebase -i HEAD~数字

・分割したいコミットにeditと記述する！！
pick gh21f6d ヘッダー修正
pick 93054e 　　ファイル追加
edit 84gha0d READNE修正

・コミットがリセットする！！
$ git reset HEAD^

そこから現状の確認で、git statasで確認する！
そこから git add ファイル名 を行っていき、コミットしていく！！！

最後に
＄　　git rebase --continue
```

##git  タグの一覧表示
```
$ git tag

$ git tag -l 日付　　//日付の指定も可能
```

##git タグを作成する（注釈付きタグ）
```
$ git tag -a タグ名　-m "メッセージ"
```

##git タグを作成する（軽量版タグ）
```
$ git tag タグ名
```

##git　タグのデータを表示する
```
$ git show タグ名 もしくは　日付
```

##git タグをリモートリポジトリに送信する
```
$git push リモート名　タグ名

・タグを一斉送信する
$ git push origin --tags
```

##git 作業を一時避難する
```
$ git stash
$ git stash save
```

##git 避難した作業を確認する
```
$ git stash list  //避難した一覧を表示する
```

##git　避難した作業を復元する
```
・最新の作業を復元する
$ git stash apply

・ステージの状況も復元する
$ git stash apply --index

・特定の作業を復元する
$ git stash apply スタッシュ名
$ git stash apply stash@{数字}　　　　　　　　　　　//git stash listで確認すること
```

##git　避難した作用を削除する
```
・最新の作業を削除する
$ git stash drop

・特定の作業を削除する
$ git stash drop スタッシュ名
$ git stash drop stash@{数字}

・全作業を削除する
$ git stash clear
```
Githubにpushする方法

#やりたいこと
ローカルのファイルをGithub上にpushする。

#Githubとは
エンジニアが各々のプログラムをアップして自分以外のエンジニアと共有する場所
![vJ9K9dP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/805284/71e54ffb-f115-c116-fed6-83694263c38d.png)

#サンプルファイル
今回は例として下記のtest.htmlを使用し、Githubに上げてみます。

```
<html>
<head>
<title>Hello world !</title>
</head>
<body>
<h1>Hello world !</h1>
</body>
</html>
```

1. 対象フォルダに移動

```
cd test
```
2.Gitリポジトリ作成 - 対象フォルダをGit管理対象に設定

```
git init
```

3.現在の状態を確認

```
git status
```
すると、まだインデックスに登録されていないため、下記のようなエラーが出る。
インデックスとは、ローカルリポジトリとリモートリポジトリの間の場所。
Gitではコミットした時に、リモートリポジトリにダイレクトにコミットするのではなく、その間にあるインデックスにあるものをコミットするようにしている。

```
On branch master

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        test.html

nothing added to commit but untracked files present (use "git add" to track)
```

4.インデックスに追加する

```
git add test.html
```

5.コミット -  インデックスにあるファイルをコミット

```
git commit -m "add new file"
```

6.リモートリポジトリに接続

```
git remote add origin (自身のリモートリポジトリのURL)
```

7.リモートリポジトリにpush

```
git push origin master
```

追記
ブランチ作成

```
git branch -M ブランチ名
```

作成したブランチにpush

```
git push -u origin ブランチ名
```
AWSの勉強してるときよく見る単語集その①

## はじめに
こんにちは！初めまして！喜村といいます！
今回はクラウドインフラの一つであるAWSの資格であるSAAやDVAを勉強しているときによく出てくる単語をざっくり纏めました。

よろしくお願いします！(｡･ω･)ﾉﾞ

##　API 
　AWSだけに限らずWeb系の仕事に関わってくるとよく出てくる**API**。これは「**Application Programming Interface**」の頭文字です
　英文字だけで意味を理解しようとすると、アプリケーション・プログラミング・インターフェイスで、大雑把に言うと**アプリケーションをプログラミングするためのインターフェース**という意味です。

##　インターフェース
　APIで出てきた単語インターフェースってなんでしょう？？
　これは**「何か」と「何か」を繋げるもの**です。例えばUSBも「パソコン」と「周辺機器」を繋ぐものですのでインターフェースの一つになります。
　
##　プロビジョニング
　プロビジョニングとは、**必要に応じてネットワークやコンピューターのなどの設備やリソースを提供できるように予測し、準備しておくこと**。
　供給や設備等の意味を表すプロビジョンという単語が元となって派生した単語です。
　試験ではよくElastic BeanstalkやCloudFormationに関わる問題に出る単語

##　レイテンシ
　レイテンシとは**データ転送における指標のひとつで、転送欲求を出してから実際にデータが送られてくるまでに生じる通信の遅延時間**のこと。
　この遅延時間が短いことをレイテンシが小さいだったり遅延時間が長いことをレイテンシが大きいと表現したりします。
　試験ではよくELBやRoute53に関わる問題によく出る単語

##　ロードバランシング（負荷分散）
　負荷分散とは、文字の通り**同種の複数の機器やシステムの間で、負荷がなるべく均等になるように処理を分散して割り当てること**。そのような負荷の振り分けを行う聞きやシステムをロードバランサーという。
　AWSではELBが負荷分散してくれる

##　オートスケール
　オートスケールとは**サーバーの負荷に応じて自動的にクラウドサーバーの台数を増減させる機能のこと**。
　システムにアクセスが集中したときはサーバーを自動で増やし、アクセスが少ない時はサーバーを自動で減らし常に必要最小限のサーバー数でシステムを安定的に稼働させることができる。
　AWSのサービスではAutoScallingがこれ

##　レプリケーション
　レプリケーションとは**レプリカ（複製）をつくること**。
同じネットワーク内や遠隔地にサーバーを設置してリアルタイムでデータをコピーする技術のこと。
　マスターのデータベースと全く同じ内容のデータベースを作成できるため、負荷分散やホットスタンバイに有効な手段として普及しています。万が一障害が起こっても、システムを停止させることなく継続でき、予備を遠隔地に置くことで広域災害時の対策としても有効です。
　AWSではRDS・Aurora・S3とかの問題によく出る

##　リソース
　リソースとは**資源や資産という意味のこと。**パソコンやサーバーそのものやCPU・メモリといった構成要素の性能、容量であったり開発プロジェクトに投入される人的資源や予算のこと。
　
##　ミドルウェア
　ミドルウェアとは**コンピュータを構成する要素の一つで、処理を行うアプリケーションと制御をするOSとの間に存在するソフトウェアのこと**。
　簡単に言うと、OSとアプリケーションの中間に位置して色々やってくれるヤツです笑

##　ワークロード
　ワークロードとは**仕事量、作業不可などの意味を持つ英単語**。ITの分野ではコンピュータやシステムにかかる処理の負荷の大きさを指すことが多い

##　ソリューション
　ソリューションとは**顧客の抱える問題・課題を解決したり要望・要求を満たすことが出来る製品やサービス**のこと

##　アーキテクト
　アーキテクトとは**システムや製品の全体的な設計を行う技術者を指すことが多い**。
　情報システムやソフトウェアの開発において、全般的な構造（アーキテクチャ）の設計や、基礎・中核部分の設計や仕様策定、全体のプロジェクト管理などを行うことが出来る技術者やそのような業務に関わるチームなどのこと。

##　アソシエイト
　アソシエイトとは**補佐する役割を担う人を指す「準」「副」を表す**。

##　さいごに
　さいごの3つの単語は合わせるとSAA（ソリューションアーキテクト・アソシエイト）になります。
　間違ってる部分や意味が違うというご指摘があれば随時変更していきますのでコメントお待ちしております！！

(｡･ω･)ﾉﾞバイバイ
PyCaretのMLflowへのトラッキングが参考になりそうという話

## 概要
PyCaretではMLflowへのトラッキングを自動で実施できるのですが、トラッキングしている項目が参考になるため、自動トラッキングを行うノートブック群を作成したので共有します。

2021年6月21日現在、下記のノートブックが動作します。

- pycaret_regression
- pycaret_classification


下記については、setupがなぜか完了しませんでした。

- pycaret_clustering
- pycaret_anomalydetection


## 想定実行環境

- Databricks
    - Databricks Runtime Version:8.3 ML (includes Apache Spark 3.1.1, Scala 2.12)

※注1 Databricks Community Editionで実行する場合、MLflowへのトラッキングの仕様が異なることから、適切に動作しない可能性があります。

## 手順
### 1. 下記URLのdbcファイルをインポート

```URL
https://github.com/manabian-/mlflow_reference_from_pycaret/blob/main/src/mlflow_reference_from_pycaret.dbc
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/5dff3e2e-abb8-7fbe-3003-7ed314b32346.png)

### 2. `main`のノートブックを実行

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/8e792781-f3fb-3067-4216-cb5890586202.png)

### 3. `pycaret_code`配下にあるノートブック（例：pycaret_regression）を表示して、右上にある`Experiment` -> `View Experiment　UI`を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/1320df07-168a-1708-5354-1e1fb8b73ef5.png)

### 4. `Models`に`skleran`がある行を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/80d17ec0-3dfa-beb7-c487-3e87592aacb7.png)

### 5. トラッキングされている項目を確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/4cc75877-55b8-2f80-33e0-81b266775953.png)
【Google Cloud Day'21】「SIer におけるマルチクラウド戦略と Anthos の活用」を視聴して

https://cloudonair.withgoogle.com/events/google-cloud-day-digital-21/watch?talk=d2-appdev-06
SIer におけるマルチクラウド戦略と Anthos の活用
"SIer がコンテナとマルチクラウドに取り組み、なぜ Anthos を採用するのでしょうか？
JBCC では SI 案件にコンテナを活用して、お客様がやりたいことを素早く実現できることを目指しています。
本セッションでは、SIer からみた Anthos で実現出来る価値と、弊社が SI 案件でお客様に提供していきたい価値をビジネスと技術の両方の視点でご紹介します。"

<table>
	<tr>
		<th>質問</th>
		<th>回答</th>
	</tr>
	<tr>
		<th>DBをなぜAnthos上ではなく、別に構築するようにしているのでしょうか？分けている理由を教えて下さい。</th>
		<td>現時点では、PaaSのDBを使ったほうが構築も運用も楽だと考えています。将来的にはKubernetes Operatorを使ってDBもコンテナにすることも検討してみたいと思っています。</td>
	</tr>
	<tr>
		<th>各クラウド環境のスキルセットにもよると思いますし、定量的には言えないと思いますが、各環境毎にクラスタを運用するのと比べ、Anthosの利用でどの程度クラスタ管理が楽になると感じますか？</th>
		<td>数値で表現するのはむずかしいのですが、他の人にスキル展開をする点ではかなり楽になるかと思ってます。特にCNIまわりはクラウドに合わせて理解する必要性が小さくなりました。</td>
	</tr>
	<tr>
		<th>Azure、AWS、Google Cloud すべてを利用されるのでしょうか。マルチクラウド環境を用意できるという点ではいいですが、特にプラットフォームにこだわらない場合、逆に言うと 1つだけでも問題ないように思われますが。どういう場合にクラウドを使い分けるのでしょうか </th>
		<td>お客様からのリクエストで選ぶケースがおおいです。既にクラウド構築されている場合は合わせたいという感じです。</td>
	</tr>
	<tr>
		<th>マルチクラウドを管理する製品はAnthos以外に他社製品も選択肢があると思いますが、Anthosを選択した理由はなんですか？</th>
		<td>一番大きな点はマルチクラウド、従量課金で利用できる点です</td>
	</tr>
	<tr>
		<th>Anthosである程度共通化できるものの、一部は各クラウドサービス個別に設定が必要だと読み取れましたが、Anthosで共通化出来る/できないの線引きはどの辺に設定していますか？</th>
		<td>一番わかりやすいところでは、ロードバランサーまわりは、各クラウドで個別の設定が必要になります。</td>
	</tr>
</table>


<table>
	<tr>
		<th>切り口</th>
		<th>内容</th>
	</tr>
	<tr>
		<th>会社概要</th>
		<td></td>
	</tr>
	<tr>
		<th>超高速開発</th>
		<td>Paasを使って開発。ツールを使ってローコードで開発</td>
	</tr>
	<tr>
		<th>顧客の課題</th>
		<td>運用については、中小の課題</td>
	</tr>
	<tr>
		<th>マルチクラウド展開時の課題</th>
		<td>Paasはインフラ目線で違いがある。３つの課題を一気に解決してくれるのはGKEだけだった。管理系はGoogleCloudに集約できる</td>
	</tr>
	<tr>
		<th>アーキテクチャ</th>
		<td></td>
	</tr>
	<tr>
		<th>CICD共通基盤</th>
		<td></td>
	</tr>
</table>

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/058aebe8-05d4-347f-e13a-9b1a5fff8d19.png)
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/58c24e63-35f5-b912-1e0c-3e7dccc9fe48.png)
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/ef999cd3-b607-b46c-1642-be596c63ac7f.png)
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/b341832b-7220-c11e-dbb1-94fc67fd6e4a.png)
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/91d7b127-f31c-b34d-6c3e-22108c81f435.png)
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/7e075bcb-b7a9-e575-fc78-6d24cb271332.png)
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/81001685-38ae-81be-ce3b-6c70c12cb7c5.png)
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/0e6eaad4-04a6-473b-8030-4adbb118a471.png)
![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/90d822f8-f4e5-e804-2eb4-58e9bd1c1110.png)
![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/af45a477-abf2-38a2-22ab-582206da3402.png)
![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/fb335f31-ce2e-17f6-dccc-a49c41fb249a.png)
仮想MFAデバイスの設定時に発生した「エンティティは既に存在しています」の調査

# 仮想MFAデバイスの設定時に発生した「エンティティは既に存在しています」の調査

## 背景

社内の方からAWSを利用したいのでアカウントの作成を依頼されました。
アカウントの作成後、セキュリティ強化のため、設定登録を必須としているMFAデバイスの登録を依頼。
ところが、以下のようなエラーが発生してしまいました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589067/b773e3f4-c55d-0b2d-7d05-2f28239d40c4.png)


## 参考

[AWS MFA 設定で「エンティティは既に存在しています」エラーの解決方法](https://qiita.com/codenote_net/items/055d1265d9fbb7ee142b)

## 環境

せっかくなので、先日構築したdocker desktop for Windowsに移設(コピー)したaws-cliのコンテナで作業してみることにします。

[]()

## コンテナの起動

まずはdocker desktop for Windowsからコンテナを起動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589067/f74640cd-88c4-2142-5f90-8f086a38cdbf.png)

しばらくすると起動しますので、「cli」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589067/200cf6f9-1eb8-3755-6953-6cf11bfd2e57.png)

別ウィンドウでcliが起動します。
早速調査を開始しします。

詳細は割愛しますが、最初にaws configureを設定し、awsとの疎通を確認しておきます。

```
# aws configure
AWS Access Key ID [None]: xxxxxxxxxx
AWS Secret Access Key [None]: xxxxxxxxxx
Default region name [None]: us-west-1
Default output format [None]: json

# aws sts get-caller-identity
{
    "UserId": "xxxxxxxxxx",
    "Account": "xxxxxxxxxx",
    "Arn": "arn:aws:iam::xxxxxxxxxx:user/xxxxxxxxxx"
}
```

## list-virtual-mfa-devices で問題の SerialNumber を特定

こちらのコマンドを実行することで、仮想MFAデバイスのリストを取得できるようです。
実行してみたところ、エラーが発生しているIAMユーザのデバイスが登録されていることがわかりました。



```
# aws iam list-virtual-mfa-devices
{
    "VirtualMFADevices": [
        {
            "SerialNumber": "arn:aws:iam::xxxxxxxxxx:mfa/xxxxxxxxxx"
        },
        {
            "SerialNumber": "arn:aws:iam::xxxxxxxxxx:mfa/root-account-mfa-device",
            "User": {
                "UserName": "xxxxxxxxxx",
                "UserId": "xxxxxxxxxx",
                "Arn": "arn:aws:iam::xxxxxxxxxx:root",
                "CreateDate": "2016-06-24T01:42:38+00:00",
                "PasswordLastUsed": "2020-02-19T07:06:41+00:00"
            },
            "EnableDate": "2019-07-24T07:15:06+00:00"
        },
：
：
：

```



## delete-virtual-mfa-device で該当のデバイス情報を削除



listコマンドと同様にdeleteコマンドも用意されているようなので、該当のIAMユーザのデバイス情報を削除してみます。



```
# aws iam delete-virtual-mfa-device --serial-number "arn:aws:iam::xxxxxxxxxx:mfa/xxxxxxxxxx"
```



実行後は何もプロンプトにメッセージは表示されませんでしたので、再度LISTを取得し、正しく削除されていることを確認できました。



IAMユーザの利用者に連絡し、再度MFAデバイスの登録を実施してもらったところ、エラーは解消されており、無事にMFAデバイスの登録を行うことができました。

## おわりに

実は当初、この方法を見つけることができず、別のIAMユーザを作成し、利用者の方に払い出し、AWS環境を利用してもらっていました。
しかし、根本的な解決にはなっていませんでしたので、今回調査と対処を実施、無事に解決に至りました。
エラーメッセージからして二重登録なのだろうとは思いましたが、調査方法や対処方法がすぐに出てこず、時間がかかってしまったのが反省点です。
[VBA] エクセルファイルを開いたり閉じたりする


Excel VBAからエクセルファイル(ブック)を扱う方法です。

### オブジェクト
`Workbookオブジェクト`がブックを表しています。
このオブジェクトを管理しているのが`Workbooksオブジェクト`です。
単語の最後に`s`が付いただけです。Workbookの複数形です。
管理しているといいましたが、いわゆるコンテナです。
開いているブック全てが格納されています。
これから開くブックに対してもこのオブジェクトから呼び出します。

### 特別なブック
上記のWorkbooksオブジェクトを使わずにアクセスできるブックがあります。
まず、VBA(実行しているマクロ)が入っているブックで、`ThisWorkbook`で表します。
もう一つ、アクティブになっているブックを`ActiveWorkbook`で表すことができます。

`ThisWorkbook.Path`でパスが取得できます(基点となるのでよく使います)。
`ThisWorkbook.Name`でファイル名が取得できます(まぁ、使いませんけど)。
ActiveWorkbookはあまり使いません。明記していない場合はActiveWorkbookが補完されることが理由の一つ、さらに、Excelでは新たに開いたブックが自動でActiveWorkbookになってしまうことから、実行環境によって意図しない結果になる可能性があるからです。

### ブックを開く
Workbooks(Workbookの管理者)に`.Add`や`.Open`メソッドを使ってブックを開きます。
これらのメソッドは`開いたブックオブジェクト`を返すので、`set + 変数 =`で受け取ります。

#### 新規ブック

```vb
Dim wb As Workbook
Set wb = Workbooks.Add
```

#### 既存のブック
既存のブックを開くにはパスが必要です。

```vb
Dim wb As Workbook
Set wb = Workbooks.Open(Filename:=パス)
```

パスは相対パスでも絶対パスでも使うことができます。

#### 名前を付けて保存
`SaveAs`メソッドを使います。引数にパス(ファイル名)を指定します。

```vb
wb.SaveAs Filename:=パス
```

#### 閉じる
`Close`メソッドを使います。
個人的には`savechanges:=false`を付けることが多いです(ほぼ全て)。
この引数は「変更あるけど保存しなくていいの？」というエクセルからのメッセージを出さないようにするものです。
事前に保存していれば問題ありません。

```vb
wb.Close savechanges:=False
```

### 小技
#### 開く速度を上げる
エクセルはブックを開いた際、いろいろなことをやっているようです。
再計算してみたり、画面描写を計算したり。
ブックを開く速さはブックの容量によっても変わります。
出来るだけ早くする方法がいくつかあります。

- 画面描写を止める
- イベントを止める
- 再計算を止める

```vb
' 止める
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual

' ここに処理を記述

' 元に戻す
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
Application.ScreenUpdating = True
```

場合によっては再計算が必要なときもあります。
イベントのことはついつい忘れてしまいます。
なのでマクロが動いているのを見る必要がなければ画面描写(ScreenUpdating)を止めるだけでかなり速くなります。

##### ReadOnlyを付けて少しだけ速く開く、そして安心感を得る
読み込み専用で開くことで、ほんの少し早く開けるようです。
また、データを変更してしまったかもしれないという不安を除いてくれます。

Openメソッドの引数にReadOnly:=Trueを追加します。

```vb
Set wb = Workbooks.open(Filename:=パス, ReadOnly:=True)
```

### おわり
流れとしては、実行ファイル(ThisWorkbook)は手動で開きます。
以降はマクロで、データを保管するファイルを開き(Addで作る)、
データの元が入っているファイルも開いて、保管ファイルにデータを移したりします。
元ファイルが複数ある場合は、処理済みのファイルは閉じてから、新しいファイルを開きます。
なので同時に開いているのは３ファイルということになります。
ただ、数千ファイルを連続で開いて～閉じて～、 開いて～閉じて～とやっていくと、挙動がおかしくなることがあります。
私の経験では5,000ファイルを超えるとアクティベートが変わったり、すごく時間がかかったりします。
面倒ですが、2,000ファイル位に分割して処理することをおすすめします。
Docker環境をUbuntuからWindowsへ移設(コピー)し起動する

# Docker環境をUbuntuからWindowsへ移設(コピー)し起動する

## 背景

もともと、サブ機でUbuntuを稼働させており、そこでDockerやDocker-Composeを
利用できるような環境を構築していました。
今回、有志との活動の一環で、Windows上にDocker Desktopを構築したのですが、
その環境でも愛用していたaws-cliが利用できるコンテナを使いたくなり、
UbuntuからWindowsに移設(コピー)して両環境で利用できるようにしたいと考えました。

## 目的・やりたいこと

・ Windows10上のDocker Desktopでaws-cliが利用できるコンテナを稼働させる。
・ 実際にAWSにアクセスしてaws-cliが利用できることを確認する。

## 環境

・ Windows環境に、Docker DesktopとGit for Windows がインストールされていること。
・ AWSにaws-cliでアクセスできること(アクセスキー、シークレットアクセスキーを入手済みであること)

## 関連記事

[WindowsにDocker Desktopをインストールする](https://qiita.com/Yoshihito-Fukushima/items/0bcd629095218dc81ede)

## 手順

まずはUbuntu環境からWindows環境へコンテナ起動に必要なファイルをコピーします。
コピー方法はいろいろあると思いますのでここでは割愛します。

最初に、Docker Desktopを起動します。

次に、コンテナ軌道に必要なファイルが格納されているフォルダにエクスプローラでアクセス。
フォルダ内で右クリックし、「Git Bash Here」をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589067/e4f43172-d5b2-9dfd-2dcf-16ae0b82a25e.png)

以下のコマンドを実行し、コンテナを起動します。

```
$ docker-compose run --rm aws-cli bash
```

ですが、Git for Windowsで実行すると、Ubuntu上で実行したときと動作が異なり、
プロンプトが帰ってきてくれませんでした。

```
$ docker-compose run --rm aws-cli bash
Creating aws_aws-cli_run ...
Creating aws_aws-cli_run ... done
```

Docker Desktopを見ると起動はしているようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589067/ccad7ff2-7181-bdfc-1d22-905acef47e23.png)

cliボタンがあるのでこちらをクリックしてみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589067/614e5362-8c6f-49a2-5307-a845f63ee417.png)

すると、別ウィンドウでコンソールが表示されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589067/33a51f28-8bb4-96aa-0e5e-4dd0a9f2cd2b.png)

ここからだと、普通にコマンドが打てるようでした。
ちょっとした操作の違いはあれど、何とか使えそうです。

aws-cliを利用するために、aws configureを実行し設定します。

```
# aws configure
AWS Access Key ID [None]: xxxxxxxxxx
AWS Secret Access Key [None]: xxxxxxxxxx
Default region name [None]: xxxxxxxxxx
Default output format [None]: json
```

試しにiamユーザ一覧でも取得してみます。
無事に実行でき、情報を取得できていることが確認できました。

```
# aws iam list-users --query 'Users[].UserName' 
```

## 最後に

aws-cliというコンテナ名ですが、このコンテナではansibleもkubectlも実行できるので
実はとても重宝しているコンテナだったりします。
(プロセス分離の考え方には反しているかもしれないとは思っていますが．．．)

dockerの特性なので当たり前のことなのですが、環境が異なってもちゃんと起動でき、
しかも同じ環境を手に入れることができました。

知識としては理解していましたが、実際に異なる環境で起動させてことはなかったので
今回はとても良い検証となりました。
Contentful更新時にCloudflareのAPI叩いてCloudflare Pagesのデプロイを走らせる

# はじめに
こんにちは。所用でしばらく家を空けていたら保管期限が1日過ぎた郵便物の不在票が...。
差出人に戻ってしまいました、筆者です :innocent: 

さて、以下記事で個人ブログのホスティング先を**Netlify**から**Cloudflare Pages**に引越しました。

https://qiita.com/akitkat/items/671ed0a47b6ca1c8b191

それに伴って、Contentful更新時にデプロイできなくなってしまったので、その設定をしました！
参考になれば幸いです！

# 方針
**Contentful**のWebhookで**Cloudflare API**のデプロイを行うエンドポイントを叩きます。
エンドポイントはこちらです。

https://api.cloudflare.com/#pages-deployment-create-deployment

# Contentful更新時にCloudflareのAPI叩いてCloudflare Pagesのデプロイを走らせる

## 1. Cloudflareから必要な値を取得する

**Cloudflare API**でデプロイするエンドポイントを叩くため、以下の値が必要なります。

1. アカウントID
2. プロジェクト名
3. 登録メールアドレス
4. APIキー

### 1.1. アカウントIDの確認方法

ホームから対象のドメインページへ移動。

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86984/b0fc5cd6-d3bc-d7d4-0391-37c59e730f61.png)

遷移後のページの右サイドバーにあります。

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86984/fa459388-3a39-68d5-560a-0a3987fbd750.png)


### 1.2. プロジェクト名の確認方法

ホームから**ページ**へ移動。

![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86984/f012adf8-2872-2ff1-9a4c-9d1741aa018d.png)

デプロイ対象のプロジェクトに表示されます。

![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86984/93c9672c-cad5-3b9b-91df-81c3a76eff64.png)

### 1.3 登録メールアドレスの確認方法

**アカウントアイコン**にマウスホバーすると確認できます。

![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86984/2a584443-0588-3b3a-45e7-c2c039537e1c.png)

### 1.4. APIキーの確認法

プロフィールページに行きます。

![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86984/d909241c-239a-7a9c-8b78-2feaca7be249.png)

**APIトークンタブ**に移動し、**Global API Key**の**表示**を押下し**パスワードの入力**で表示できます。

![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86984/f2e24286-4424-9cd9-ee0a-4027448eec75.png)

## 2. ContentfulでWebhookの設定画面を開く

以下から設定が行えます。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86984/c97dc8e6-c421-da0e-d0ee-15d6948db0b1.png)

今回は新規作成します。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86984/3b320b94-f6f8-eb84-f496-870c42fdb2c2.png)

## 3. Webhookの設定を行う

設定項目は以下の通りです。

1. Name
1. URL(POST)
1. Triggers
1. Headers

### 3.1. Name
任意の値で設定してください。

### 3.2. URL
**Cloudflare API**のエンドポイントを設定します。

Cloudflareで取得した、アカウントIDとプロジェクト名をURLに埋めてURLを生成します。

```
https://api.cloudflare.com/client/v4/accounts/CF_ACCOUNT_ID/pages/projects/CF_PROJECT_NAME/deployments
```

### 3.3 Triggers
お好みのトリガーを設定してください。
自分はEntryの**Publish**と**Unpublish**と**Delete**のみです。

### 3.4. Headers

以下2つを設定します。
いずれも先ほどCloudflareで取得した値を使用します。

1. X-Auth-Email
2. X-Auth-Key

## 設定値確認

全体で見ると以下の感じです。
数字が付いているところが先ほどCloudflareで取得した各値の番号と連動しています。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86984/90112770-c2bb-858a-4d04-852dcb5f70bc.png)

## 完了
あとはContentfulでEntryを更新等すれば**Cloudflare Pages**のデプロイが走ります！

# おわりに
無事に設定が終わりました :v:
これで快適なContentfulでの記事更新ができます :ok_hand: 

Lighthouse等のテストを行いたい場合は、GitHub Actionsに渡して実行というのもできます:ok_hand:

お好みでどうぞ！
それでは！
技術メモ：LWC lightning-datatable改ページ行番号の設定

データ量が多いの場合、datatableに複数ページ表示するつもりですが、毎ページ行番号は1から再計算しまいました。
データ総量連番したいですので、以下の設定が必要

```html
<lightning-datatable 
show-row-number-column 
key-field="id" 
data={data} 
row-number-offset={rowOffset} 
columns={columns}>
```
<font color="red">**※show-row-number-column設定必要、row-number-offsetのみ設定すると、効果がない**</font>

```js
    //毎ページ表示件数指定
    @track pageSize = 200;
    //開始の行番号指定
    @track rowOffset = 0;

    //ファイルの読み込みが完了したら、各変数を設定
    wiredAccounts(outputJson ) {
        if (outputJson) {
            let j = 1;
            this.items = outputJson;
            this.totalRecountCount = outputJson.length; 
            this.totalPage = Math.ceil(this.totalRecountCount / this.pageSize); 
            //画面データ表示設定、0番から
            this.data = this.items.slice(0,this.pageSize); 
            this.endingRecord = this.pageSize;
            this.paginationRange = [];
            while (this.paginationRange.push(j++) < this.totalPage) {}
            this.columns = columns;
            this.error = undefined;
            this.boolVisible=true;
        } else if (error) {
            this.error = error;
            this.data = undefined;
        }
    }

    // ページナンバーのボタンをクリックすると発火
    handlePaginationClick(event) {
        let offsetNumber = event.target.dataset.targetNumber;
        this.page = offsetNumber;
        this.displayRecordPerPage(this.page);
    }
    //画面レコードを再表示
    displayRecordPerPage(page){
        window.console.log("****page***===="+page);
        this.startingRecord = ((page -1) * this.pageSize) ;
        this.endingRecord = (this.pageSize * page);
        this.endingRecord = (this.endingRecord > this.totalRecountCount) 
                            ? this.totalRecountCount : this.endingRecord; 

        this.data = this.items.slice(this.startingRecord, this.endingRecord);
        //行番号再設定
        this.rowOffset = this.startingRecord;
        window.console.log("****rowOffset***===="+this.rowOffset);
        this.startingRecord = this.startingRecord + 1;
    }  
```
Laravelのレプリケーション遅延対策

LaravelのDBとしてAWSのAuroraを使っていてマスタースレーブ構成にしていたのですが、レプリケーション遅延により書き込んだはずのデータが見当たらないという事態が発生していました。
データを追加したユーザーが一覧ページに戻ってみると、追加したはずのデータが見当たらないというのはユーザー体験として良くないので、自分が取った対応方法について書いていこうと思います。

# 状況
コントローラの処理としては、以下のようなstoreアクションで書き込んだ後リダイレクト先のindexアクションで読み込みをしていて、この読み込みの際に書き込んだデータが反映されていないという現象が5回に1回程度発生します。


```MenuController.php
<?php

namespace App\Http\Controllers\Web\Professional;

use Illuminate\Routing\Controller;
use App\Models\Menu;

class MenuController extends Controller
{
    public function index(FetchOrderedMenusService $service)
    {
        $menus = Menu::all();
        return view('menu.index', compact('menus');
    }

    public function store(Request $request)
    {
        Menu::create($request->all());
        return redirect()->route('menus.index');
    }
}
```

Auroraのレプリカラグが20ms、書き込み処理からリダイレクトして読み込み直前までの時間を計測すると約100msなので、読み込みのタイミングでスレーブに反映されていないということは無い気がするのですが、たまたまレプリケーションに時間がかかったというのとリクエストの処理時間が早かったという状況が重なって発生しているのではと考えました。
実際に対策をすると今回の現象は発生しなくなりました。

# 対策
### 方針
`config/database.php`の`sticky`を有効化している場合だと、同一リクエスト上ではマスターに書き込みを行った後はマスターを参照するようになります。ただ、今回はリダイレクトしたときにマスターを参照して欲しいので`sticky`を有効化するだけでは対応できません。

`sticky`を有効化している場合の処理を追ってみると、`DB::recordsHaveBeenModified()`を呼び出すことでそれ以降の処理ではマスターを参照するようだったので、この関数を使って書き込み直後のリクエストでマスターを参照させます。

### 実装
以下のようなミドルウェアを作成し、既存の実装に影響が出ないようにします。
ミドルウェアの実装内容としては、DBに書き込みを行った直後のリクエストかどうかを判別できるように書き込みのタイミングでセッションに値を保存しておき、次のリクエストでセッションに値が存在すれば`DB::recordsHaveBeenModified()`を呼び出します。

```php
<?php

namespace App\Http\Middleware;

use Closure;
use DB;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;

class UseWriteConnectionWhenHaveBeenModified
{
    public function handle(Request $request, Closure $next, ...$modelClassNames): mixed
    {
        $callback = function () {
            session()->flash('haveBeenModified');
        };

        foreach ($modelClassNames as $modelClassName) {
            if (!is_subclass_of($modelClassName, Model::class)) {
                continue;
            }

            $modelClassName::created($callback);
            $modelClassName::updated($callback);
            $modelClassName::deleted($callback);
        }

        if (session()->has('haveBeenModified')) {
            DB::recordsHaveBeenModified();
        }

        return $next($request);
    }
}

```

書き込み直後のリクエストを処理し終わったらセッションから値が削除されて欲しいので`flash`関数を使っています。

作成したミドルウェアをコントローラから利用できるように`Kernel.php`に追記します。

```app/Http/Kernel.php
protected $routeMiddleware = [
    ...
    'haveBeenModified' => \App\Http\Middleware\UseWriteConnectionWhenHaveBeenModified::class,
];
```

最後にコントローラのコンストラクタにミドルウェアを追加します。

```MenuController.php
public function __construct()
{
    $this->middleware('haveBeenModified:' . Menu::class);
}
```

指定したeloquentモデルのデータに書き込み処理が行われると、直後のリクエストはマスターを参照するようになります。
kintoneでサブテーブルの行追加時に上の行をコピーする

タイトル通り、kintoneのサブテーブルの行追加時に上の行の内容をコピーする小技です。

# アプリの準備

文字列(1行)のフィールドをテーブルにしましょう。

| フィールド種類 | フィールドコード | 備考 |
|:-:|:-:|:-:|
|  文字列(1行) | 品名  | テーブルのフィールド  |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/fc022359-6964-bf1e-ba14-4a319ac2a35b.png)

# JavaScript

使うのは下記イベント。

レコード追加画面のフィールド値変更時イベント
レコード編集画面のフィールド値変更時イベント

テーブルの行追加があった場合や行削除があった場合に発火するイベントです。

```js
kintone.events.on(
  ["app.record.edit.change.テーブル", "app.record.create.change.テーブル"],
  (event) => {
    // 軽率に変数名hinmeiを定義
    let hinmei = "";
    event.record.テーブル.value.forEach((r) => {
      // 値がない場合（追加した行）はhinmeiで上書きする
      if (!r.value.品名.value) {
        r.value.品名.value = hinmei;
      } else {
        // 値がある場合（入力済の行）はhinmeiに値を入れておく
        hinmei = r.value.品名.value;
      }
    });
    return event;
  }
);
```

# まとめ
下の行が空だったら自動的に上の行の値をコピーして埋めてくれます。
（上の行が空っぽだったら空文字がコピーされます）
試してみてくださいね！

![aaaa.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536148/4faf75fa-aeb9-51a3-bbdb-0148e7b75a54.gif)
PowerShellでNAS内に同じファイルがあるかを調べる

仕事でたくさんのPDFファイルを扱うのですがコピーも多いので、NASに同じファイルがあるかを調べるスクリプトを作りました。

#NASのファイル一覧をCSVファイルに出力する

NASへのファイルアクセスを減らしたいので、一旦NASの中のファイル情報（フルパス、ファイルサイズ、最終書き込み日時）をCSVファイルに出力します。下のスクリプトをNASの検索対象のフォルダで実行して`filelist.csv`を作成します。

```powershell:NASのデータを集める
Get-ChildItem *.pdf -Attributes Archive -Recurse | Select-Object Name,FullName,Length,LastWriteTime | Export-Csv filelist.csv -Encoding UTF8
```

#ファイルを検索する

先のスクリプトで出力された`filelist.csv`を検索したいファイルがあるフォルダに移動して下のスクリプトを実行します。

```powershell:ファイルを検索する
$m = Import-Csv filelist.csv -Encoding UTF8
Get-ChildItem *.pdf -Attributes Archive -Recurse | ForEach-Object {
  $h = (Get-FileHash $_.FullName -Algorithm SHA256).Hash
  $s = 'None'
  foreach($t in $m){
    if (($_.Length -eq $t.Length) -And ([DateTime]::$_.LastWriteTime -eq [DateTime]::$t.LastWriteTime)){
      if ($h -eq (Get-FileHash $t.FullName -Algorithm SHA256).Hash){
        $s = $t.FullName
        break
  }}}
  Write-Host $_.FullName,$s
}
```

プログラムは、「ファイルサイズ」が同じで、「最終書き込み日時」が同じで、「SHA256のハッシュ値」が同じであるかを調べています。（コピーするとファイル名が変更される場合があるので、ファイル名が同じであるかは調べていません。）
[Ruby] AtCoder Beginner Contest 205 B問題

##はじめに
AtCoderの過去問にハマってしまいました　笑
今回はAtCoder Beginner Contest 205 B問題**「B - Permutation Check」**にRubyで挑戦です！よろしくお願いします。

問題文は下記リンクから飛んで確認してください。

https://atcoder.jp/contests/abc205/tasks/abc205_b

##問題 B - Permutation Check
まずは入力を受け取る記述です。

```Ruby
n = gets.to_i
a = gets.split.map(&:to_i)
```

正直のところ、入力値の受け取り方からかなり苦労してます。
慣れみたいなところはあるのでしょうが、まだまだ記述に困ってしまいます。

入力を受け取る記述ができたらまず、空の配列を作ります。
受け取った、nの数字分１からこの配列に入れていきます。

例えばnが6だったら、1, 2, 3, 4, 5, 6 という配列が欲しいので、その配列を作成するための記述を書いていきます。

```Ruby
n = gets.to_i
a = gets.split.map(&:to_i)
ary =[]
n.times do |nn|
  ary << nn + 1
end
```

ブロック変数の名前が思いつかなくて、めちゃくちゃ悪い例だと思います。。。
こういう時のわかりやすい名前の付け方とかあればぜひコメントにて教えていただけると幸いです。

nn + 1　としているのは、もし+ 1していないと、0 ~ 5になってしまうからです。（配列は添字で要素を管理しているため）

ここまでくれば、あとはこの配列aryの中の数字が、aの中の数字と一致しているか(順番は関係ない）を調べて、全て一致していればYesを出して、一つでも違えばNoを出力してやれれば完成です。

```Ruby
n = gets.to_i
a = gets.split.map(&:to_i)
ary =[]
n.times do |nn|
  ary << nn + 1
end
 
if ary.all? { |i| a.include?(i) }
  puts "Yes"
else
  puts "No"
end
```

これで完成です。ポイントはこのall?メソッド。
このall?メソッドとinclude?メソッドの組み合わせを見つけるのに苦労しました。

##おまけ

all?メソッドの使い方を説明します。まず、書き方は下記のとおりです。

```
オブジェクト.all? { |要素| ブロック処理 }
```




all?メソッドは配列の中身を全て取り出し、ブロック変数に一つずつ入れていきます。そして、{}のなかに書かれている処理の返り値が全て真の時にtrueを返すメソッドです。

include?メソッドは()の中の要素が、配列の中にあるかを調べ、存在すればtrueを返します。

つまり、先ほどの回答の記述は、all?メソッドで配列aryの中の要素全てがブロック変数iに一つずつ代入され、include?メソッドの()の中に入ることによって、変数aの中に、aryから取り出した要素があるかどうかを調べています。

そして、全てのaryの要素が配列aの中に存在すると判断されればall?メソッドが初めてtrueを返します。

##最後に
これまであまりアルゴリズムには触れてこなくて、初めて見るメソッドが多かったりします。何回も繰り返して使いこなしたいと思いました。
今回のall?メソッドは大きな収穫です！
Pytest ブレイクポイント の設置方法

## テストコードが実装できるpytestでブレイクポイント の設置方法について明記します

使うコードは1つの関数だけ

```
breakpoint()
```
これを自分のコード内の自由な場所に記述するだけでライブラリのインポートも必要ありません。

## 実行方法について

```qiita:test.py
class TestQiita(object):

    def test_success_case(self):
        sum = 0
        for i in range(10):
            breakpoint() # 今回はここにブレイクポイントを設置
            sum += i
```
 
ターミナル実行でオプションに `--pdb` を追加して実行

```qiita:terminal
$ pytest test.py --pdb
```

実行後、(Pdb)が表示されたら、その横に確認したい変数を手入力してEnter。（今回は i を確認)

```
(Pdb) i
0
```

control + 'D'キー で次へ進み、次は `sum` を確認

```
(Pdb) i
0
(Pdb) sum
0
```

 ひとまず、メモがわりに記述しておきます。

参考サイト
qiita.com/Kohey222/items/19eb9b3cbcec9b176625
Python で質的変数のヒストグラム作成

# はじめに
データの基礎分析で質的変数の度数分布図（ヒストグラム）を作る必要がある場面になったとき、`matplotlib` の `hist` では少し物足りなくなった事情があったので、備忘録として記事に残しておく。

# データセットの準備
データセットは質的変数が含まれていればなんでもいいので、iris の場合の例を示す。

```python:
#モジュールのインポート
from sklearn import datasets
import pandas as pd
import matplotlib.pyplot as plt

#（量的変数は使わないけど）データセットの読み込み
iris = datasets.load_iris()
df = pd.DataFrame(iris.data)

#質的変数のラベルを追加する。
df['species'] = iris.target
df.loc[df['species'] == 0, 'species'] = "setosa"
df.loc[df['species'] == 1, 'species'] = "versicolor"
df.loc[df['species'] == 2, 'species'] = "virginica"

print(df)
```

```:出力
       0    1    2    3    species
0    5.1  3.5  1.4  0.2     setosa
1    4.9  3.0  1.4  0.2     setosa
2    4.7  3.2  1.3  0.2     setosa
3    4.6  3.1  1.5  0.2     setosa
4    5.0  3.6  1.4  0.2     setosa
..   ...  ...  ...  ...        ...
145  6.7  3.0  5.2  2.3  virginica
146  6.3  2.5  5.0  1.9  virginica
147  6.5  3.0  5.2  2.0  virginica
148  6.2  3.4  5.4  2.3  virginica
149  5.9  3.0  5.1  1.8  virginica
```

# `hist`を使ったプロット
質的変数（ラベルデータ等…）でも`hist`でヒストグラムが作成できる。

```python
fig1 = plt.figure()
plt.hist(df["species"])
plt.show()
fig1.savefig("iris_speacies_hist.png")
```

![iris_speacies_hist.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1077734/87ffe7e5-90f3-b592-624c-8d01669b4be6.png)


しかし、完成したプロットを見て頂ければ分かる通り、setosa, versicolor は種類名がグラフの左側にあるのに対して、virginica はグラフの右側にある。種類の数が少なければ大きな問題には見えないが、種類が増えるとプロットが重なる原因になってしまう。何より不均一なのが気持ち悪い。

# 度数分布表を作成し、`bar`を使ったプロット
上記の問題を解消するため、度数分布表を別途作成し、`bar`によってヒストグラムを描く方法を取る。

```python
#度数分布を辞書型で作成
col = set(df["species"])
data = df["species"].tolist()
dosu = { key: data.count(key) for key in col}
ind = range(len(dosu.keys()))

#プロット部分
fig2 = plt.figure()
plt.xticks(ind, dosu.keys())
plt.bar(ind, dosu.values())
plt.show()
fig2.savefig("iris_speacies_bar.png")
```

![iris_speacies_bar.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1077734/4fa3251c-2eb1-2b8f-9d82-eabe96f82379.png)

これによりきちんと種類名の真ん中にラベルが来て、見やすいヒストグラムとなった。

# おわりに
質的変数を可視化する際にはちょっとした処理が必要だったので、そのメモを残すために記事を書いた。もし、`hist`を使ってきれいに図がかける方法をご存じの方が居れば、是非コメントお願いします！
Amazon CloudWatch Logs Insight サンプル集

あまりサンプルがないように思えたのでメモとして残しておく

1000文字以上のメッセージを出力

```
fields @timestamp, @message, strlen(@message) as str_len
| sort str_len desc
| filter strlen(@message) > 1000
| limit 200
```

Lambdaの課金処理時間が1000ms以上のものを抽出

```
fields @timestamp, @message
| parse @message '*Billed Duration: * ms*' as m1, lambda_time, m3
| filter lambda_time > 1000
| limit 200
```
【備忘録】WSL2でのimport, exportとログイン設定

#はじめに
研究室のパソコン、ノートパソコン、自宅のパソコンはすべてWindoes10 + WSL2 + Windows terminalを使っていたのだが、設定（コンパイラ、プログラム, vimrcなど)の共有があまりにも面倒くさいのでなにかないかな、と探していたところ以下のサイトを発見。

https://forest.watch.impress.co.jp/docs/serial/yajiuma/1220926.html

WSL2はdockerコンテナみたいimport, exportが自在にできるようです。（嬉しい）
以下、備忘録として共有します。
#環境
Windows 10 Home
WSL2 (Ubuntu20.04)
ターミナル: Windows terminal

#export 
研究室PCにて、Ubuntu20.04 (共有したいlinux) をlabuntu.tar (名前は任意) ファイルに出力。

```powershell:Powershell
wsl --export Ubuntu-20.04 ./labuntu.tar
```

私の環境ではimport完了まで数分かかりました。ドキドキ。
（このコマンドだと何も進捗表示されません）

#import

さきほどの.tar（数GBになった)を研究室PCからノートパソコンに持っていった。
以下ノートPCのpowershellにて

```powershell:Powershell
mkdir ~/AppData/Local/labuntu
wsl --import labuntu ~/AppData/Local/labuntu ./labuntu.tar --version 2
```
こちらもexportと同様import時に数分待ちました。
wslコマンドを打つとき --version2を打ち忘れましたが wsl -l -vで確認したらちゃんとWSL2でimportされているみたいでした。
一応ここでimport自体は完了ですがこのままだと少々厄介なことが起きます。

#厄介な仕様

ログインするとなぜか強制的にrootログインになってしまう謎事象。
https://tech-drive.net/pc/2018062701/
こちらの分かりやすい記事を参考させてもらい、powershellから設定変更をかける。

```powershell:powershell
Function WSL-SetDefaultUser ($distro, $user) { Get-ItemProperty Registry::HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Lxss\*\ DistributionName | Where-Object -Property DistributionName -eq $distro | Set-ItemProperty -Name DefaultUid -Value ((wsl -d $distro -u $user -e id -u) | Out-String); };
WSL-SetDefaultUser labuntu kojihattori
```
一行目は有志の方がつくられた関数みたいですね。
・参考　https://github.com/Microsoft/WSL/issues/3974
二行目distro-name とusernameは適宜読み替えてください。


また、WSL2のホームディレクトリがデフォルトではwindows側のホームディレクトリになってしまうので、windows terminalのGUIから”デレクトリの開始”を設定変更。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308853/65a1e941-b6d7-c7df-e3a6-02c6de8ee6d8.png" width=250px">

以上でok。

＜おまけ＞
WSLのimport後に強制的にrootユーザになったとき、suで通常のユーザには戻れるが通常ユーザからsuでrootに戻れない。。パスワードなんだっけ。。？ということがあった。

結論から言うとWSLではrootユーザのパスワード初期設定がなく、絶対にsuがauthentication failureになるとのことでした。　（https://matsudamper.hatenablog.com/entry/2020/01/06/173939）
CodeDeployエージェントのメモリ問題

## 事象
codepipelineから「変更をリリース」したところ、CodeDeployでコケた。

エラー

```
2021-06-16 09:47:03 ERROR [codedeploy-agent(2559)]: InstanceAgent::Plugins::CodeDeployPlugin::CommandPoller: Error during perform: Errno::ENOMEM - Cannot allocate memory - rm -rf /opt/codedeploy-agent/deployment-root/b59fab18-5d0f-41bf-92e8-60410f9c6597/d-HCQHTD03B 2>&1 - /opt/codedeploy-agent/lib/instance_agent/platform/linux_util.rb:95:in
```

メモリを割り当てられないらしい。

## 原因
デプロイ先のEC2インスタンスのメモリが80%を超えていた。

プロセスのメモリ使用率の割合を調べてみると、CodeDeployエージェントが異常にメモリ使っていた。53.8%

```
ps aux --sort -rss
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      2559  0.0 53.8 1508016 1098544 ?     Sl    5月13  23:05 codedeploy-agent: InstanceAgent::Plugins::CodeDepl
```

## 対応

CodeDeployエージェント再起動をすることでメモリ使用率が53.8%から2.7%になった。

## 今後の対応

CodeDeployエージェント再起動後にCodeDeploy実行を複数回行い、プロセスのメモリ使用率の上り具合を確認する。
codedeployエージェントメモリ使用率：　2.7　→　13.6　→　22.1　→　22.2　→　23.0　→　23.5　→　25.2　...


結果
CodeDeploy実行する度にプロセスのメモリ使用率が大きく上がっていくことがわかった。
現状、定期的にCodeDeployエージェントの再起動を行わなければ、今回のようにメモリを割り当てられなくなり、CodeDeploy実行時にエラーになる。

こちらの参考サイトを元に以下対応
https://github.com/aws/aws-codedeploy-agent/issues/32

対応１

参考サイトによると、デプロイメントバンドルの解凍に使用されているサードパーティのメモリ内ライブラリが原因。```unzip```がインストールされていればメモリ使用量を小さくすることが出来るらしい。

しかし当サーバーではunzipはインストール済みだった。
確認コマンド```yum info unzip```

対応2

参考サイトによると、根本解決ではないが以下で回避はできる。

appspec.ymlファイルのValidateServiceフックから実行されるスクリプトにCodeDeployエージェントの再起動をスケジュールする行を追加

```
at -M now + 2 minute <<< $'service codedeploy-agent restart'
```

処理内容：CodeDeploy実行の2分後にCodeDeployエージェントの再起動を行う。
（atコマンドのオプション```-M```に関して探しても出てこなかったのでつけないで設定）

[AppSpecのフックセクション](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/reference-appspec-file-structure-hooks.html)

appspec.yml　（編集）

```
version: 0.0
os: linux

files:
  - source: src
    destination: /var/www/html/

permissions:
  - object: /var/www/html
    owner: apache
    group: apache

hooks:
  ValidateService: // 追加
    - location: deploy/codedeploy-restart.sh // 追加
runas: root
```

deploy/codedeploy-restart.sh　（新規作成）

```
at now + 2 minute <<< $'service codedeploy-agent restart'
```

### 動作確認

CodeDeployログでシェルが実行されていることを確認

```
less /opt/codedeploy-agent/deployment-root/deployment-logs
[2021-06-16 14:49:04.709] [d-N7S12UG4B]Script - deploy/codedeploy-restart.sh
```

複数回デプロイを実行してCodeDeployエージェントのメモリ使用率が上がらないことを確認

```
ps aux --sort -rss
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root     16779  0.2  2.7 331548 55792 ?        SNl  14:52   0:00 codedeploy-agent: InstanceAgent::Plugins::CodeDeploy
```