るいすのブログ

オタクエンジニアの雑記

Private Link + ECR を試す

概要

従来は ECR からコンテナイメージを取得するために、IGW、NATGW を使用していたが、
Private Link の登場によりこれらが不要になった。

料金や、セキュリティの観点から Private Link 経由での方がメリットが多い。

料金について


Private Link
$ 0.014 * 720 = $ 10.08
$ 0.01 per 1GB processed


NAT GW
0.062 * 720 = $ 44.64(月額固定)
$ 0.062 per 1GB processed

検証環境

Fargate

  • cluster: hasegawa-ecr-privatelink
  • vpc: vpc-03dd
  • subnet: subnet-0a45

ECR

  • hasegawa-privatelink

S3

  • hasegawa-privatelink

VPC エンドポイントの作成

3つのエンドポイントを作成する。

  • com.amazonaws.us-west-2.ecr.dkr
  • com.amazonaws.us-west-2.s3
  • com.amazonaws.us-west-2.logs

ECR へのエンドポイント

f:id:rarirureluis:20200402190817p:plain

S3 へのエンドポイント

f:id:rarirureluis:20200402190916p:plain

コンテナイメージの実態は S3 にある。

CWL へのエンドポイント

f:id:rarirureluis:20200402191019p:plain

コンテナが CWL へ書き込む際に必要。

ECR エンドポイントの SG

f:id:rarirureluis:20200402191119p:plain
443 でイメージを取りに来るのでインバウンドに Fargate で使う SG を追加する。

動作確認

実際に Private Link 経由で ECR からイメージを引っ張って動作確認をする。

使用したイメージをこれ
hub.docker.com

イメージの URL は ECR のままで大丈夫。
number.dkr.ecr.us-west-2.amazonaws.com/hasegawa-privatelink:latest

f:id:rarirureluis:20200402191738p:plain
public ip は不要

f:id:rarirureluis:20200402191617p:plain
デフォルトゲートウェイもなし

確認

f:id:rarirureluis:20200402191648p:plain

問題なく、イメージを引っ張って動作確認できた。

MySQL innodb_buffer_pool_instances を調整したら幸せになれました

1 分間に約 23万クエリ流れる DB が全部で 4台な環境がある。
f:id:rarirureluis:20200324135113p:plain

innodb_buffer_pool_size はだいたい 70 GB

セマフォ

innodb_buffer_pool_instances を調整することで、mutex への競合が減りパフォーマンスが向上する。

innodb_buffer_pool_instances = 1

f:id:rarirureluis:20200324161003p:plain

OS Waits: 2,383,265
Spin Waits: 60,1417

innodb_buffer_pool_instances = 20

f:id:rarirureluis:20200324161058p:plain

OS Waits: 1,522
Spin Waits: 27,1328

バッファプール

mutex への競合が減ることによってパフォーマンスが向上し、バッファプールが効率よく使える様になった。
今回の場合、バッファプールがいっぱいになったのでディスクへの読み書きが増えることを確認できた。

innodb_buffer_pool_instances = 1

f:id:rarirureluis:20200324162304p:plainf:id:rarirureluis:20200324162304p:plain

Read: 5.37 IOPS
Write: 337.8 IOPS

innodb_buffer_pool_instances = 20

f:id:rarirureluis:20200324162442p:plain

Read: 32.7 IOPS
Write: 404.2 IOPS

結果

スロークエリ、レプリ遅延が無くなり幸せになれました。

innodb_buffer_pool_instances = 1

f:id:rarirureluis:20200324135315p:plain

スロークエリ: 250
レプリ遅延: 1

innodb_buffer_pool_instances = 20

f:id:rarirureluis:20200324135713p:plain

スロークエリ: 0
レプリ遅延: 0

ちなみに Aurora とかはどうなってるかというと

Aurora 5.6.10a m5.2xlarge (MEM: 64GB) でしか確認してないけど innodb_buffer_pool_instances = 8 になっていた。
MySQL 5.6 の innodb_buffer_pool_instances はデフォルトで 1 だけど、ここは流石の AWS 様でした。

ECS と distroless イメージの組み合わせは悲しい

最近見るプロジェクトが増えました。

ECS コンテナのヘルスチェックにいつもどおり何かを書く

CMD,curl,localhost

しかし、永遠に UNKNOWN になる。

使ってるイメージを持ってきてローカルで確認してみる。

$ luis@ubuntu ~ $ docker run --name test -it --rm --entrypoint "bash"
docker: Error response from daemon: OCI runtime create failed: container_linux.go:346: starting container process caused "exec: \"bash\": executable file not found in $PATH": unknown.
$ luis@ubuntu ~ $ docker run --name test -it --rm --entrypoint "sh"
docker: Error response from daemon: OCI runtime create failed: container_linux.go:346: starting container process caused "exec: \"sh\": executable file not found in $PATH": unknown.
$ luis@ubuntu ~ $ docker run --name test -it --rm --entrypoint "curl"
docker: Error response from daemon: OCI runtime create failed: container_linux.go:346: starting container process caused "exec: \"curl\": executable file not found in $PATH": unknown.

どうやって、Docker イメージを作ってるのか調べてみると jib とかいうのを使ってるらしい。
そこにベースのイメージを指定できるのだけど

jib {
    from {
        image = "gcr.io/distroless/java:11"
    }
    ...
}

gcr.io/distroless/java:11 をベースイメージに作ってるらしい。

github.com

They do not contain package managers, shells or any other programs you would expect to find in a standard Linux distribution.

なるほど。

Stripe Checkout をローカルの Vue で動作確認する

f:id:rarirureluis:20200310020008p:plain
Stripe Checkout のホワイトリストドメインリストに localhost は使えない。

Stripe Checkout を動作させるには

hosts を書き換える

127.0.0.1 hoge.com

Vue.js のホスト名チェックを切る

devServer: {
    disableHostCheck: true
}

https で webpack dev server を起動する

$ yarn dev --https

動作確認

https://hoge.com:8080 にアクセスする。
ローカル環境から Stripe Checkout 使えた。

f:id:rarirureluis:20200310020349p:plain

コンテナで動かしてる MySQL で innodb_dedicated_server = 1 にしたらどんどん死んでいった話

ある日 InnoDB Cluster をコンテナ上で動かしてたがメモリを期待していた以上に消費していたので調べていた。

その時は innodb_dedicated_server を 1 にしてた。

innodb_dedicated_server

MySQL 8.0 から追加された変数で自動で innodb_buffer_pool_size とかを自動で決めてくれる便利もの。
dev.mysql.com

ソースを覗いてみる

下記ソースコードたちは MySQL 8.0.18 のやつ

buffer_pool_size が決まるところ

ha_Innodb.cc:3992 で innodb_dedicated_server が ON の場合の分岐が走り、
ha_innodb.cc:3999 でサーバーにあるメモリ量を取得して innodb_buffer_pool_size が決まる。

ha_innodb.cc の innodb_buffer_pool_size_init 部分 ↓

/** Initialize and normalize innodb_buffer_pool_size. */
static void innodb_buffer_pool_size_init() {
#ifdef UNIV_DEBUG
  ulong srv_buf_pool_instances_org = srv_buf_pool_instances;
#endif /* UNIV_DEBUG */

  acquire_sysvar_source_service();
  /* If innodb_dedicated_server == ON */
  if (srv_dedicated_server && sysvar_source_svc != nullptr) {
    static const char *variable_name = "innodb_buffer_pool_size";
    enum enum_variable_source source;
    if (!sysvar_source_svc->get(
            variable_name, static_cast<unsigned int>(strlen(variable_name)),
            &source)) {
      if (source == COMPILED) {
        double server_mem = get_sys_mem();

        if (server_mem < 1.0) {
          ;
        } else if (server_mem <= 4.0) {
          srv_buf_pool_size = static_cast<ulint>(server_mem * 0.5 * GB);
        } else
          srv_buf_pool_size = static_cast<ulint>(server_mem * 0.75 * GB);
      } else {
        ib::warn(ER_IB_MSG_533)
            << "Option innodb_dedicated_server"
               " is ignored for"
               " innodb_buffer_pool_size because"
               " innodb_buffer_pool_size="
            << srv_buf_pool_curr_size << " is specified explicitly.";
      }
    }
  }
  release_sysvar_source_service();

  if (srv_buf_pool_size >= BUF_POOL_SIZE_THRESHOLD) {
    if (srv_buf_pool_instances == srv_buf_pool_instances_default) {
#if defined(_WIN32) && !defined(_WIN64)
      /* Do not allocate too large of a buffer pool on
      Windows 32-bit systems, which can have trouble
      allocating larger single contiguous memory blocks. */
      srv_buf_pool_instances =
          ut_min(static_cast<ulong>(MAX_BUFFER_POOLS),
                 static_cast<ulong>(srv_buf_pool_size / (128 * 1024 * 1024)));
#else  /* defined(_WIN32) && !defined(_WIN64) */
      /* Default to 8 instances when size > 1GB. */
      srv_buf_pool_instances = 8;
#endif /* defined(_WIN32) && !defined(_WIN64) */
    }
  } else {
    /* If buffer pool is less than 1 GiB, assume fewer
    threads. Also use only one buffer pool instance. */
    if (srv_buf_pool_instances != srv_buf_pool_instances_default &&
        srv_buf_pool_instances != 1) {
      /* We can't distinguish whether the user has explicitly
      started mysqld with --innodb-buffer-pool-instances=0,
      (srv_buf_pool_instances_default is 0) or has not
      specified that option at all. Thus we have the
      limitation that if the user started with =0, we
      will not emit a warning here, but we should actually
      do so. */
      ib::info(ER_IB_MSG_534)
          << "Adjusting innodb_buffer_pool_instances"
             " from "
          << srv_buf_pool_instances
          << " to 1"
             " since innodb_buffer_pool_size is less than "
          << BUF_POOL_SIZE_THRESHOLD / (1024 * 1024) << " MiB";
    }

    srv_buf_pool_instances = 1;
  }

#ifdef UNIV_DEBUG
  if (srv_buf_pool_debug &&
      srv_buf_pool_instances_org != srv_buf_pool_instances_default) {
    srv_buf_pool_instances = srv_buf_pool_instances_org;
  };
#endif /* UNIV_DEBUG */

  srv_buf_pool_chunk_unit = buf_pool_adjust_chunk_unit(srv_buf_pool_chunk_unit);
  srv_buf_pool_size = buf_pool_size_align(srv_buf_pool_size);

  ut_ad(srv_buf_pool_chunk_unit >= srv_buf_pool_chunk_unit_min);
  ut_ad(srv_buf_pool_chunk_unit <= srv_buf_pool_chunk_unit_max);
  ut_ad(srv_buf_pool_chunk_unit % srv_buf_pool_chunk_unit_blk_sz == 0);
  ut_ad(srv_buf_pool_chunk_unit % UNIV_PAGE_SIZE == 0);
  ut_ad(0 ==
        srv_buf_pool_size % (srv_buf_pool_chunk_unit * srv_buf_pool_instances));
  ut_ad(srv_buf_pool_chunk_unit * srv_buf_pool_instances <= srv_buf_pool_size);

  srv_buf_pool_curr_size = srv_buf_pool_size;
}

メモリサイズを返しているところ

get_sys_mem() でサーバーに割り当てられたメモリ量を取得している。

ha_innodb.cc:297 ↓

static double get_mem_sysconf() {
  return (((double)sysconf(_SC_PHYS_PAGES)) *
          ((double)sysconf(_SC_PAGESIZE) / GB));
}
_SC_PHYS_PAGES

物理メモリのページ数

_SC_PAGESIZE

バイト単位でのページサイズ

MySQL はメモリの管理方式としてはページング方式を使っていて物理メモリのページ数と1ページ辺りのサイズをかけて返してるらしい。
_SC_PHYS_PAGES は物理マシンのページ数を返すのでコンテナ(プロセス)で動かす場合では不都合が起きる。

似たようなことを経験したことがあったからある程度予測はついていた。
blog.luispc.com

C 読めないし、MySQL Server はソースが膨大でコンパイルして開くまで30分かかった。
間違ってたら(補足があったら)教えてくれると助かります🙏

GTID で errant transaction に悩んだら

TL;DR

  • flush slow logs のタイミングでバイナリログに書き込まれる
  • それによって GTID がズレる = errant transaction
  • このスクリプトを mackerel-agent で定期実行することで解決

事象

あるタイミングでスレーブの GTID が進んで errant gtid が起きる。

flush slow logs はバイナリログに書かれるよ

FLUSH PRIVILEGESやFLUSH TABLESはバイナリーログに書かれるのでgtid_executedに記録されるよ

バイナリログを調べる

general_log に書かれる server id はもちろんスレーブの。 バイナリログのは server id は、マスターの server id になる。

↓ こんなスクリプトで調べていった。

#!/bin/bash
    
logs=(000003 000004 000005 000006 000007 000008 000009 000010 000011 000012 000013 000014 000015)
    
for log in "${logs[@]}"
do
  mysqlbinlog /var/lib/mysql/mysql-bin.${log} --result-file=/mnt/data/output_${log} -v
  echo "${log}: $( cat /mnt/data/output_${log} | grep 'server id 101941095' |wc -l )"
done

これの出力結果はこんな感じになる ↓

000003: 3
000004: 3
000005: 3
000006: 3
000007: 3
000008: 3
000009: 3
000010: 5
000011: 3
000012: 3
000013: 3
000014: 3
000015: 3

server_id: 101941095 がバイナリログ上に出現した数が出力される。 3 は正常で、それ以上が怪しいやつ。

つまり、mysql-bin.000010 が怪しい。

mysql-bin.000010 を調べる

    # at 418792896
    #200216  3:12:01 server id 101941095  end_log_pos 418792944 CRC32 0xe049bbeb    GTID [commit=yes]
    SET @@SESSION.GTID_NEXT= 'ac8a2a1b-31d2-11ea-ad13-fa163eee324c:11'/*!*/;
    # at 418792944
    #200216  3:12:01 server id 101941095  end_log_pos 418793022 CRC32 0x1b3c4ada    Query   thread_id=3743  exec_time=0     error_code=0
    SET TIMESTAMP=1581790321/*!*/;
    SET @@session.sql_mode=1075838976/*!*/;
    flush slow logs
    /*!*/;
    # at 418793022
    # #200216  3:12:01 server id 101941095  end_log_pos 418793022 CRC32 0x1b3c4ada    Query   thread_id=3743  exec_time=0     error_code=0
    # SET TIMESTAMP=1581790321/*!*/;
    # SET @@session.sql_mode=1075838976/*!*/;
    # flush slow logs
    # /*!*/;
    # # at 418793022
    # //
    SET TIMESTAMP=1581803224/*!*/;
    BEGIN
    /*!*/;

flush slow logs ... :thinking_face:

(寄り道)3 回出現する理由

気になる。

1回目

# at 4
#200215 14:22:31 server id 101941095  end_log_pos 120 CRC32 0x64963fc6  Start: binlog v 4, server v 5.6.44-log created 200215 14:22:31
BINLOG '
F4BHXg9nfxMGdAAAAHgAAAAAAAQANS42LjQ0LWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAAXAAEGggAAAAICAgCAAAACgoKGRkAAcY/
lmQ=
'/*!*/;

起動時。 これが何をしているのかは不明なので教えてください。

2回目

# at 121
#200215 14:22:31 server id 101941095  end_log_pos 471 CRC32 0x725344f8  Previous-GTIDs
# 54a349d8-311a-11ea-a861-fa163efc07d0:1-10,
# 7aab7d0a-32f1-11ea-b461-fa163e7976a1:1-10,
# 7ac09f23-32f1-11ea-b461-fa163ed61f9a:1-502880417,
# 864f8199-0b58-11ea-b22c-fa163eb7e9f7:1-892916580,
# ac8a2a1b-31d2-11ea-ad13-fa163eee324c:1-10,
# d46dd772-0b58-11ea-b22e-fa163ee8afa4:1-10,
# d7128fda-0b58-11ea-b22e-fa163e9f03bc:1-1778530447,
# fef8730c-45b7-11ea-aed0-fa163e09984a:1-10

GTID の仕様上で、過去に実行してきた GTID を全て知っている必要がある。 バイナリログの先頭には、↑ のように今まで実行した GTID を記録し、gtid_executed に保存される。

3回目

# at 1073741881
#200215 16:29:17 server id 101941095  end_log_pos 1073741928 CRC32 0xdecb3708   Rotate to mysql-bin.000003  pos: 4
DELIMITER ;
# End of log file

新しいバイナリログへのローテート時

原因

まさにこれだった。

FLUSH PRIVILEGESやFLUSH TABLESはバイナリーログに書かれるのでgtid_executedに記録されるよ

確認

flush slow logs を叩いてみる。

before

f:id:rarirureluis:20200217152638p:plain

after

f:id:rarirureluis:20200217152649p:plain

ac8a2a1b-31d2-11ea-ad13-fa163eee324c:1-14ac8a2a1b-31d2-11ea-ad13-fa163eee324c:1-15 になった。無事、errant transaction の完成です。

解決

flush slow logs をやめるのは流石にキツイのでスクリプトを回す。

Orchestrator を Mackerel と組み合わせて幸せを掴むスクリプト - ちゃんるいすのブログ

はてなシンタックスハイライトって、shell とか bash とか無いんだ、、、(今更)

Orchestrator を Mackerel と組み合わせて幸せを掴むスクリプト

なにしてるの

  • errant transaction の検知
  • errant transaction の修正
  • can-replicate-from-gtid を叩く

errant transaction の検知

function check_errant {
  for cluster in "${CLUSTERS[@]}"
  do
    replicas=( $( orchestrator -c which-replicas -i "${cluster}") )

    for replica in "${replicas[@]}"
    do
      local result=$( orchestrator -c which-gtid-errant -i "${replica}" )
      if [ -n "${result}" ]; then
        inject_empty_transaction "${replica}"
      fi
    done
  done
}

レプリカが errant transaction を持っていた場合は、
inject_empty_transaction を実行する。

local result=$( orchestrator -c which-gtid-errant -i "${replica}" )
if [ -n "${result}" ]; then
  inject_empty_transaction "${replica}"
fi

errant transaction の修正

function inject_empty_transaction {
  local replica="${1}"
  orchestrator -c gtid-errant-inject-empty -i "${replica}"
}

なんで問答無用で inject empty transaction してるかというと、、、
次の記事に書く予定。

can-replicate-from-gtid を叩く

function can_replicate {
  for cluster in "${CLUSTERS[@]}"
  do
    replicas=( $( orchestrator -c which-replicas -i "${cluster}") )

    for replica_i in "${!replicas[@]}"
    do
      for other_i in "${!replicas[@]}"
      do
        if [ ${replica_i} -eq ${other_i} ]; then
          continue
        fi

        source_replica="${replicas[${replica_i}]}"
        destination="${replicas[${other_i}]}"

        set +e
        result=$( orchestrator -c can-replicate-from-gtid -i "${source_replica}" -d "${destination}" )
        if [ $? -ne 0 ]; then
          echo -e "${source_replica} to ${destination} cannot replicate\nError: ${result}\nCheck errant gtid http://<orchestrator ip>:3000/web/cluster/alias/prd-dbs07"
          exit 2
        fi
        set -e
      done
    done
  done
}

マスターを除く全てのレプリカ同士でレプリケーションが貼れるかどうかを調べる。

Mackerel で使う

[plugin.checks.can_replicate_from_gtid]
command = "bash /usr/local/bin/canreplicate.sh"
notification_interval = 10
max_check_attempts = 3
check_interval = 3

max_check_attempts = 3 こうしてるのはタイミング悪いと can-replicate-from-gtid が失敗するから(register-candidate とタイミングが被ると良くないっぽい)

CentOS 8 で mysql-community-server 8.0.19 を入れる

dnf め...

mysql repo を入れる

# dnf install https://dev.mysql.com/get/mysql80-community-release-el8-1.noarch.rpm -y

mysql-community-server を探す

# dnf list | grep mysql-community-server
mysql-community-server-debug.x86_64                  8.0.19-1.el8                                      mysql80-community
mysql-community-server-debug-debuginfo.x86_64        8.0.19-1.el8                                      mysql80-community
mysql-community-server-debuginfo.x86_64              8.0.19-1.el8                                      mysql80-community

あれ、、、?

mysql module を切る

# dnf -y module disable mysql

探す

# dnf list | grep mysql-community-server
mysql-community-server.x86_64                        8.0.19-1.el8                                      mysql80-community
mysql-community-server-debug.x86_64                  8.0.19-1.el8                                      mysql80-community
mysql-community-server-debug-debuginfo.x86_64        8.0.19-1.el8                                      mysql80-community
mysql-community-server-debuginfo.x86_64              8.0.19-1.el8                                      mysql80-community


😋

snmp_exporter の generator で Edge Router のメトリクスを取る

これを使う
grafana.com

generator.yml

↑ の generator.yml は古い書き方で現在の generator では使えない。
こうする ↓

modules:
  edgemax:
    walk:
      - ifHCInOctets
      - ifHCOutOctets
      - ssCpuIdle
      - memTotalFree
      - memTotalReal
      - hrSystemUptime
    lookups:
      - source_indexes: [ifIndex]
        lookup: 1.3.6.1.2.1.31.1.1.1.1
        drop_source_indexes: false

snmp.yml

生成したやつ

# WARNING: This file was auto-generated using snmp_exporter generator, manual changes will be lost.
edgemax:
  walk:
  - 1.3.6.1.2.1.31.1.1.1.1
  - 1.3.6.1.2.1.31.1.1.1.10
  - 1.3.6.1.2.1.31.1.1.1.6
  get:
  - 1.3.6.1.2.1.25.1.1.0
  - 1.3.6.1.4.1.2021.11.11.0
  - 1.3.6.1.4.1.2021.4.11.0
  - 1.3.6.1.4.1.2021.4.5.0
  metrics:
  - name: hrSystemUptime
    oid: 1.3.6.1.2.1.25.1.1
    type: gauge
    help: The amount of time since this host was last initialized - 1.3.6.1.2.1.25.1.1
  - name: ifHCOutOctets
    oid: 1.3.6.1.2.1.31.1.1.1.10
    type: counter
    help: The total number of octets transmitted out of the interface, including framing
      characters - 1.3.6.1.2.1.31.1.1.1.10
    indexes:
    - labelname: ifIndex
      type: gauge
    lookups:
    - labels:
      - ifIndex
      labelname: ifName
      oid: 1.3.6.1.2.1.31.1.1.1.1
      type: DisplayString
  - name: ifHCInOctets
    oid: 1.3.6.1.2.1.31.1.1.1.6
    type: counter
    help: The total number of octets received on the interface, including framing
      characters - 1.3.6.1.2.1.31.1.1.1.6
    indexes:
    - labelname: ifIndex
      type: gauge
    lookups:
    - labels:
      - ifIndex
      labelname: ifName
      oid: 1.3.6.1.2.1.31.1.1.1.1
      type: DisplayString
  - name: ssCpuIdle
    oid: 1.3.6.1.4.1.2021.11.11
    type: gauge
    help: The percentage of processor time spent idle, calculated over the last minute
      - 1.3.6.1.4.1.2021.11.11
  - name: memTotalFree
    oid: 1.3.6.1.4.1.2021.4.11
    type: gauge
    help: The total amount of memory free or available for use on this host - 1.3.6.1.4.1.2021.4.11
  - name: memTotalReal
    oid: 1.3.6.1.4.1.2021.4.5
    type: gauge
    help: The total amount of real/physical memory installed on this host. - 1.3.6.1.4.1.2021.4.5
luis@ubuntu ~/snmp_exporter-master/generator $ vi                                                                                                                                                                                                                         [ruby-2.6.3p62]
luis@ubuntu ~/snmp_exporter-master/generator $ cat generator.yml                                                                                                                                                                                                          [ruby-2.6.3p62]
modules:
  edgemax:
    walk:
      - ifHCInOctets
      - ifHCOutOctets
      - ssCpuIdle
      - memTotalFree
      - memTotalReal
      - hrSystemUptime
    lookups:
      - source_indexes: [ifIndex]
        lookup: 1.3.6.1.2.1.31.1.1.1.1
        drop_source_indexes: false
luis@ubuntu ~/snmp_exporter-master/generator $ cat snmp.yml                                                                                                                                                                                                               [ruby-2.6.3p62]
# WARNING: This file was auto-generated using snmp_exporter generator, manual changes will be lost.
edgemax:
  walk:
  - 1.3.6.1.2.1.31.1.1.1.1
  - 1.3.6.1.2.1.31.1.1.1.10
  - 1.3.6.1.2.1.31.1.1.1.6
  get:
  - 1.3.6.1.2.1.25.1.1.0
  - 1.3.6.1.4.1.2021.11.11.0
  - 1.3.6.1.4.1.2021.4.11.0
  - 1.3.6.1.4.1.2021.4.5.0
  metrics:
  - name: hrSystemUptime
    oid: 1.3.6.1.2.1.25.1.1
    type: gauge
    help: The amount of time since this host was last initialized - 1.3.6.1.2.1.25.1.1
  - name: ifHCOutOctets
    oid: 1.3.6.1.2.1.31.1.1.1.10
    type: counter
    help: The total number of octets transmitted out of the interface, including framing
      characters - 1.3.6.1.2.1.31.1.1.1.10
    indexes:
    - labelname: ifIndex
      type: gauge
    lookups:
    - labels:
      - ifIndex
      labelname: ifName
      oid: 1.3.6.1.2.1.31.1.1.1.1
      type: DisplayString
  - name: ifHCInOctets
    oid: 1.3.6.1.2.1.31.1.1.1.6
    type: counter
    help: The total number of octets received on the interface, including framing
      characters - 1.3.6.1.2.1.31.1.1.1.6
    indexes:
    - labelname: ifIndex
      type: gauge
    lookups:
    - labels:
      - ifIndex
      labelname: ifName
      oid: 1.3.6.1.2.1.31.1.1.1.1
      type: DisplayString
  - name: ssCpuIdle
    oid: 1.3.6.1.4.1.2021.11.11
    type: gauge
    help: The percentage of processor time spent idle, calculated over the last minute
      - 1.3.6.1.4.1.2021.11.11
  - name: memTotalFree
    oid: 1.3.6.1.4.1.2021.4.11
    type: gauge
    help: The total amount of memory free or available for use on this host - 1.3.6.1.4.1.2021.4.11
  - name: memTotalReal
    oid: 1.3.6.1.4.1.2021.4.5
    type: gauge
    help: The total amount of real/physical memory installed on this host. - 1.3.6.1.4.1.2021.4.5

使うモジュールを edgemax へ

- job_name: 'snmp'
    static_configs:
      - targets:
        - 192.168.20.1
    metrics_path: /snmp
    params:
      module: [edgemax]
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: 127.0.0.1:9116

snmp_exporter が読み込む snmp.yml を変更

生成したやつを貼り付ける。

確認

f:id:rarirureluis:20200121221242p:plain

Terrfarom じゃなくても Ansible でもできるよ!S3編

今回は S3 簡単なやつ

使うモジュール

バケットの作成

- name: Create a bucket
  s3_bucket:
    name: "{{ project }}-dbbackup"
    state: present
    region: ap-northeast-1

ライフサイクルの追加

- name: Add a lifecycle
  s3_lifecycle:
    name: "{{ project }}-dbbackup"
    storage_class: onezone_ia
    transition_days: 31
    state: present
    status: enabled

確認

f:id:rarirureluis:20200120180109p:plain


バケットポリシーも設定できます。
高度なこともできるので見てみてください。

なんでみんな Cloudflare を使わないの?無料で使える Cloudflare の機能をご紹介!

よくあるアフィ記事のタイトル風
Cloudflare 無料で色んなことできるのに周りで使っている人が少ないから布教してみる。

Cloudflare

コンテンツデリバリーネットワークやインターネットセキュリティサービス、分散型ドメイン名サーバシステムを提供するアメリカ合衆国の企業で、閲覧者とホスティングプロバイダー間でリバースプロキシとして動作する。

www.cloudflare.com

Cloudflare の日本でのシェア

https://tech.jstream.jp/blog/wp-content/uploads/2019/10/CDN-share-japanese-Oct2019.png

引用元:
tech.jstream.jp

以外に日本でのシェアがあった。
でも Cloudflare を使ってるって声をあまり聞いたことがないので企業で使っているところがあったら教えてください。

Cloudflare の企業ミッション

Cloudflare is on a mission to help build a better Internet.
かっこいい

この企業ミッションを見てから、記事の続きを見てみてください。

無料で使える

大体の必要なことは無料で使える。

(無料)証明書の用意なんてしなくても HTTPS が使える

f:id:rarirureluis:20200119185019p:plain
Cloudflare はクライアントとオリジンサーバーの間に入るリバースプロキシでもある。
例えばデフォルトの Flexible では
ユーザー →(HTTPS) Cloudflare → (HTTP) オリジンサーバー
の振る舞いを行い、何もしなくても HTTPS 接続ができる。

Cloudflare - オリジン間 も HTTPS にすることは可能で
Full or Full(strict) を選べば良い。

Full はオレオレ証明書でも可能だけど、Full(strict) はオリジンサーバー上に信頼された CA が必要になる。

(無料)オリジンサーバーの Public IP が隠せる

リバースプロキシとして作用するので、隠せる。

(無料)Page Rule によって痒いとこに手が届く

f:id:rarirureluis:20200119184601p:plain
例えば、f.easyuploader.app/*/upload/* のリクエストパスに対しておもむろにキャッシュを効かせられる。
無料ユーザーなら3つまで Page Rule が作成可能で、アカウント単位ではなくドメイン単位なので優しい。

(無料) Access 機能はまじですごい

特定のサブドメイン、または特定のパスに対してアクセス制限をかけたい場合、Cloudflare Access なら無料でできる。

f:id:rarirureluis:20200119200925p:plain
まずはプロバイダーを選択する。
ここでは Google を選択。

f:id:rarirureluis:20200119201142p:plain
次に、管理しやすいようにグループを作成する。
メール認証でも、完全一致ではなく特定のドメインの人でもできるのでご安心を。

f:id:rarirureluis:20200119200618p:plain
これは ドメイン/wordprpess/wp-admin/ に対して、Google 認証でアクセス制限をかけてる。

f:id:rarirureluis:20200119200821p:plain
実際にアクセスをすると、Google のログイン画面が出てくる。

先程のグループ email の中で設定した Google アカウントの人のみアクセスできるようになる。
仕組みとしてはログインするとポリシーを作成したときの Session Duration が有効期限の JWT が送られてくる。

f:id:rarirureluis:20200119201848p:plain

管理ツールとかも、この Access に入れればログイン機能実装しなくても使えちゃう。
中身 JWT だし。すごいよ Cloudflare Access。しかも無料で多分これは無制限に作れる。

これに加えて例えばバッチでこの Access 配下のリソースに触りたい時、特定の IP からは bypass するという機能も無料で使える。

blog.luispc.com

(無料)Rate Limit によるブルートフォースの対策もできちゃう

f:id:rarirureluis:20200119202250p:plain
この例では *.easyuploader.app に対して 1パブリックIP から1分間に50回のリクエストがあった場合に
1時間その IP をブロックするできる。

無料では1つしか作成できないけど、これもドメイン単位。すごい。

(有料)Global Load Balancer もある

月額 $5 で Global Load Balancer が使える。
一時期使ってたけど今は使ってないので画像つきで紹介はできないんですが、普通に LB です。

ファイアウォールイベントで不正なアクセスを確認できる

f:id:rarirureluis:20200119205114p:plain

アナリティクス画面も楽しい

f:id:rarirureluis:20200119205302p:plain
リクエスト数
f:id:rarirureluis:20200119205323p:plain
トラフィック
f:id:rarirureluis:20200119205343p:plain
ユニークユーザー数

Cloudflare のお陰で 3TB もキャッシュも返してくれていて、オリジンへは 100GB しか来てないのすごい。

キャッシュのパージは3秒で消える

uploader.xzy.pw
個人サービスでいくつか削除依頼でファイルを削除したりするけど、Cloudflare 上でキャッシュをパージすると3秒ぐらいでアクセスできなくなる。パージも速い。

SDK からもできるよ
func deleteCacheFromCF(fileName string) error {
    pcr := cloudflare.PurgeCacheRequest{
        Files: []string{
            fmt.Sprintf("https://f.easyuploader.app/%s/upload/%s", config.MinioBucket, fileName),
        },
    }

    _, err := cf.API.PurgeCache(cf.ID, pcr)
    return err
}

AWS のリソースとも組み合わせられる

一時期 S3 を使っていたときに、Cloudflare と組み合わせて使っていた。

s3+ CloudFront が定番だけど、s3 + Cloudflare も良い。無料だよ!

Lambda@Edge 的な Cloudflare Workers

www.cloudflare.com

Workers が Cloudflare のエッジで実行されるコンピューティングで
Workers KV が Cloudflare のネットワーク内にある KVS。

blog.luispc.com
でも正直使いみちは分からない。遅いし、、、。

無料で使ってるときの注意点

今まで Cloudflare を使ってきて2つ困ったことがあった。

サブサブドメイン

サブサブドメインで、これらの Cloudflare の恩恵を受けるには証明書を買わないといけない。
月 $5

client maximum upload size

最大で 100MB
Pro でも 100MB
Business で 200MB
Enterprise で 500+ MB

クライアントから 100MB 以上のファイルを送ってもらうには色々注意が必要。
一昔までクライアントからチャンクしてバックエンドで細かく保存して最後に1つにして、アップロードするっていう仕組みを作ったけどそれはやめて、Cloudflare を通さずに直接 minio に送るようにした。(署名付きURL)

Pro プランでも月額 $20

www.cloudflare.com

Enterprise も安いよ

詳しくは問い合わせてみてください。安いです。

Cloudflare はよく落ちるからなぁ、、、

www.itmedia.co.jp

去年は2回大きな障害があった記憶がある。
1個は Version のミス、もう1個は Cloudflare のミス。

Cloudflareは、HTTP/HTTPSインターネットトラフィック全体の10%をルーティングしており

スマートルーティングと階層型キャッシングを通じたパフォーマンス | Cloudflare

そりゃ Cloudflare が落ちたら Cloudflare は不安定という印象が付く。
でも、他の CDN だって落ちてる。

downdetector.com

社内で某 CDN のことで良くない噂も聞いたりする。
Cloudflare は不安定だから っていう理由で Cloudflare を選択肢から外すのは悲しい;;

僕も別に Cloudflare について熟知しているわけじゃないけど、CDN を選択する際にぜひ候補として考えてほしいです。
ここでは Cloudflare 全体の 3.5割ぐらいのことしか説明できませんでしたが無料なので1度触ってみてください。