togatttiのエンジニアメモ

過度な期待はしないでください.

AWS 認定ソリューションアーキテクトを受けてきた

結論

先月の終わりに、AWS 認定ソリューションアーキテクト - アソシエイトを受けて、合格した。

www.certmetrics.com

スペック

勉強期間

2週間。

勉強方法

www.udemy.com

をやりながら、AWSコンソールの操作、基本的なサービスを覚えた。

aws.amazon.com

ブラックベルトを一通り読んだ。

aws.koiwaclub.com

有料プランを申し込んで、全ての問題を解いた。

www.amazon.co.jp

これも2周くらい読み込んだ。

終わってみて

aws.amazon.com

AWSに関する基本知識が身につき、ケーススタディに書いてある各社のシステム構成図が読めるようになった。

自分も設計できる機会があればいいな。

次は、AWS 認定ソリューションアーキテクト - プロフェッショナルを目指したい。

Container Linuxにkubeadmを入れて、k8sクラスタを構築する

はじめに、Container Linuxを3台用意しておく。

  • k8s01(192.168.0.2/24)
  • k8s02(192.168.0.3/24)
  • k8s03(192.168.0.4/24)

バージョンは、こちら。

$ grep VERSION= /etc/os-release
VERSION=2023.5.0

Container Linuxの初期設定

各ホストで、パスワード、ホスト、固定IPアドレスの設定を済ませる。

パスワードの設定
$ sudo passwd core
ホストの名前設定
$ sudo hostnamectl set-hostname k8s01
$ sudo vi /etc/hosts
$ grep k8s01 /etc/hosts
127.0.0.1       localhost k8s01
固定IPアドレスの設定
### k8s01の設定
$ sudo vi /etc/systemd/network/static.network
$ sudo cat /etc/systemd/network/static.network
[Match]
Name=eth0

[Network]
Address=192.168.0.2/24
Gateway=192.168.0.1
DNS=8.8.8.8

### ネットワークの再起動
$ sudo systemctl restart systemd-networkd

kubeadmのインストール

kubeadmのインストール - Kubernetes

にあるContainer Linuxのインストール手順をrootで実行する。

$ cat install.sh
### CNIをインストール
CNI_VERSION="v0.6.0"
mkdir -p /opt/cni/bin
curl -L "https://github.com/containernetworking/plugins/releases/download/${CNI_VERSION}/cni-plugins-amd64-${CNI_VERSION}.tgz" | tar -C /opt/cni/bin -xz
### CRICTLをインストール
CRICTL_VERSION="v1.11.1"
mkdir -p /opt/bin
curl -L "https://github.com/kubernetes-incubator/cri-tools/releases/download/${CRICTL_VERSION}/crictl-${CRICTL_VERSION}-linux-amd64.tar.gz" | tar -C /opt/bin -xz
### kubeadm, kubelet, kubectlをインストール
RELEASE="$(curl -sSL https://dl.k8s.io/release/stable.txt)"
mkdir -p /opt/bin
cd /opt/bin
curl -L --remote-name-all https://storage.googleapis.com/kubernetes-release/release/${RELEASE}/bin/linux/amd64/{kubeadm,kubelet,kubectl}
chmod +x {kubeadm,kubelet,kubectl}
curl -sSL "https://raw.githubusercontent.com/kubernetes/kubernetes/${RELEASE}/build/debs/kubelet.service" | sed "s:/usr/bin:/opt/bin:g" > /etc/systemd/system/kubelet.service
mkdir -p /etc/systemd/system/kubelet.service.d
curl -sSL "https://raw.githubusercontent.com/kubernetes/kubernetes/${RELEASE}/build/debs/10-kubeadm.conf" | sed "s:/usr/bin:/opt/bin:g" > /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
### kubeletを有効にする。
systemctl enable kubelet && systemctl start kubelet
$ sudo sh install.sh

k8sクラスタ構築

マスターノード構築
### k8s01側
### クラスタの初期化
$ sudo kubeadm init --pod-network-cidr=10.244.0.0/16
### ブリッジのパケットをiptablesで処理できるようにする設定
$ sudo sysctl net.bridge.bridge-nf-call-iptables=1
$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config
### masterとして稼働していることを確認
$ kubectl cluster-info
Kubernetes master is running at https://10.200.8.117:6443
KubeDNS is running at https://10.200.8.117:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
### クラスタに参加するためのkubeadm join コマンドが発行されるので、控えておく。
ノード追加
### k8s02とk8s03側
$ sudo kubeadm join 192.168.0.2:6443 --token pu2npf.e42wltclx0f64bdc --discovery-token-ca-cert-hash sha256:9eb6af07398ebf79ef0acb0b70e18fca5f26c00912c2e132bbe634568316c347
クラスタ確認
### k8s01側
$ kubectl get nodes
NAME    STATUS     ROLES    AGE   VERSION
k8s01   NotReady   master   1m   v1.13.4
k8s02   NotReady   <none>   3s   v1.13.4
k8s03   NotReady   <none>   3s    v1.13.4
Flannel設定

クラスタが構築できたが、STATUSがNotReadyになっている。

ノードをまたいで、Pod同士が通信できるように、Flannelで、オーバレイネットワークを設定する。

### k8s01側
$ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
$ kubectl get nodes
NAME    STATUS   ROLES    AGE     VERSION
k8s01   Ready    master   5m28s   v1.13.4
k8s02   Ready    <none>   3m49s   v1.13.4
k8s03   Ready    <none>   2m23s   v1.13.4

以上で、kubeadmを用いてk8sクラスタを構築することができた。

参考

https://coreos.com/flannel/docs/latest/kubernetes.html

kubeadmを使用したシングルマスタークラスターの作成 - Kubernetes

http://sysy.livedoor.biz/archives/9791596.html

psqlで、冗長な箇所を省き結果を取得する

例えば、PostgreSQLのpg_hba.confのパスだけをpsqlで取りたいとき、

単純に、-cオプションを使うと、

$ psql -c 'SHOW hba_file'
              hba_file
-------------------------------------
 /etc/postgresql/10/main/pg_hba.conf
(1 row)

余分な箇所が混ざる。

その場合、-A -tオプションを追加すると冗長な部分を排除し期待していた結果が取得できる。

$ psql -At -c 'SHOW hba_file'
/etc/postgresql/10/main/pg_hba.conf

今までは、こんな形でシェル芸してた。

$ psql -c 'SHOW hba_file' | grep /etc | sed -e 's/ //'
/etc/postgresql/10/main/pg_hba.conf

SSHでアクセスできるEC2インスタンスを構築する

docs.aws.amazon.com

VPCの理解を深めたいと思い、上記のガイドを読みながら、SSHでアクセスできる EC2インスタンスをTerraformで作成した時の雑記です。

SSHでインターネット経由でつなげられるEC2インスタンスを構築するためには、EC2インスタンス以外に、 VPCゲートウェイ、ルーティングテーブル、セキュリティグループの設定が必要になるので作成していく。

Terraformのインストール

手元のUbuntu 18.04に、Terraformをインストールする。

# cd /usr/local/src
# wget https://releases.hashicorp.com/terraform/0.11.11/terraform_0.11.11_linux_amd64.zip
--2019-02-26 11:41:14--  https://releases.hashicorp.com/terraform/0.11.11/terraform_0.11.11_linux_amd64.zip
Resolving releases.hashicorp.com (releases.hashicorp.com)... 151.101.1.183, 151.101.65.183, 151.101.129.183, ...
Connecting to releases.hashicorp.com (releases.hashicorp.com)|151.101.1.183|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 20971661 (20M) [application/zip]
Saving to: ‘terraform_0.11.11_linux_amd64.zip’

terraform_0.11.11_linu 100%[==========================>]  20.00M  33.3MB/s    in 0.6s

2019-02-26 11:41:15 (33.3 MB/s) - ‘terraform_0.11.11_linux_amd64.zip’ saved [20971661/20971661]

# unzip terraform_0.11.11_linux_amd64.zip
Archive:  terraform_0.11.11_linux_amd64.zip
  inflating: terraform
# cp -p terraform /usr/local/bin/
# terraform version
Terraform v0.11.11

tfファイルの作成

次に、作業ディレクトリに、SSHの鍵ペアを作成する。

# su togattti
$ mkdir ~/sagyou
$ cd ~/sagyou/
$ ssh-keygen -t rsa -f id_rsa_ec2

terraform.tfvarsを作成して、変数を定義する。

aws_access_key = "xxxxxx"
aws_secret_key = "xxxxxx"
aws_region = "ap-northeast-1"
key_name = "id_rsa_ec2"
public_key = "id_rsa_ec2.pub"

ec2.tfというファイルを作成して、設定を入れる。

まず、variableを記載する。 これで、${var.aws_access_key}のtfファイルの中では、変数を通して値を参照できる。

variable "aws_access_key" {}
variable "aws_secret_key" {}
variable "aws_region" {}
variable "key_name" {}
variable "public_key" {}

AWSを使う際の初期設定を書く。

provider "aws" {
    access_key = "${var.aws_access_key}"
    secret_key = "${var.aws_secret_key}"
    region = "${var.aws_region}"
}

VPCを作成する。この中にサブネットを切り、その中でEC2インスタンスを起動する。

resource "aws_vpc" "my-vpc" {
    cidr_block = "10.0.0.0/16"
    enable_dns_hostnames = true
    enable_dns_support = true
    tags {
        Name = "my-vpc"
    }
}

VPCの中に、サブネットを作成する。

このサブネット内でEC2インスタンスを起動させる。

resource "aws_subnet" "my-subnet" {
    # cidrsubnetで計算すると10.0.32.0/19になる。
    cidr_block = "${cidrsubnet(aws_vpc.my-vpc.cidr_block, 3, 1)}"
    vpc_id = "${aws_vpc.my-vpc.id}"
    availability_zone = "ap-northeast-1a"
}

ElasticIP(固定のIPアドレス)をインスタンスに付与する。

resource "aws_eip" "my-eip" {
    instance = "${aws_instance.my-ec2.id}"
    vpc = true
}

インターネットに出るためのゲートウェイを設定する。

resource "aws_internet_gateway" "my-gw" {
    vpc_id = "${aws_vpc.my-vpc.id}"
    tags {
        Name = "my-gw"
    }
}

インスタンスからゲートウェイまでのルーティングテーブルを設定する。

resource "aws_route_table" "my-route-table" {
    vpc_id = "${aws_vpc.my-vpc.id}"
    route {
        cidr_block = "0.0.0.0/0"
        gateway_id = "${aws_internet_gateway.my-gw.id}"
    }
    tags {
        Name = "my-route-table"
    }
}

サブネットとルーティングテーブルを関連づける。

resource "aws_route_table_association" "subnet-association" {
    subnet_id = "${aws_subnet.my-subnet.id}"
    route_table_id = "${aws_route_table.my-route-table.id}"
}

ここまでで、VPCの設定が完了。

次にセキュリティグループの設定。

ingress(インターネットからインスタンスへの入りの通信)で、SSHを許可する。

resource "aws_security_group" "my-security-group" {
    name = "allow-ssh"
    vpc_id = "${aws_vpc.my-vpc.id}"
    description = "Allow SSH port"

    # inbound traffic to a instance
    ingress {
        cidr_blocks = ["0.0.0.0/0"]
        from_port = 22
        to_port = 22
        protocol = "tcp"
    }

    # outbound traffic from a instance
    egress {
        from_port = 0
        to_port = 0
        protocol = "-1"
        cidr_blocks = ["0.0.0.0/0"]
    }
}

SSHで使用する鍵ペアを設定する。

resource "aws_key_pair" "my-key-pair" {
    key_name = "${var.key_name}"
    public_key = "${file(var.public_key)}"
}

Amazon LinuxのEC2インスタンスを作成する。

resource "aws_instance" "my-ec2" {
    ami = "ami-0148288598227344a"
    instance_type = "t2.micro"
    monitoring = true
    tags {
        Name = "my-ec2"
    }
    key_name = "${var.key_name}"
    vpc_security_group_ids = ["${aws_security_group.my-security-group.id}"]
    subnet_id = "${aws_subnet.my-subnet.id}"

構築が完了したら、Elastic IPを出力する。

output "EIP for EC2 instance" {
    value = "${aws_eip.my-eip.public_ip}"
}

Terraform初期化、実行

まず、terraform initで初期化。

$ terraform init

Initializing provider plugins...

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.

* provider.aws: version = "~> 1.60"

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

terraform applyで、インスタンス構築。

$ terraform apply
(snip)

Apply complete! Resources: 10 added, 0 changed, 0 destroyed.

Outputs:

EIP for EC2 instance = 192.168.0.3

構築が完了したら、SSHしてみる。 IPは、ダミー。

$ ssh -i id_rsa_ec2 ec2-user@192.168.0.3 'hostname'
  ip-192-168-0-3.ap-northeast-1.compute.internal

作成tfファイルなどは、以下のリポジトリにおいた。

github.com

参考

Setting Up an AWS EC2 instance with SSH access using Terraform

fishでrbenvを使う

Ubuntuでfishを使っていて、rbenvの初期処理を実行する際に、詰まったので備忘録を残す。

最初に以下の記事を見つけて、config.fishを変更した。

qiita.com

設定内容はこれ。

togattti@dev ~> cat ~/.config/fish/config.fish
rbenv init - | source

でも、ログインし直したら、エラーが出た。

'case' builtin not inside of switch block
- (line 10):   case "$command" in
               ^
from sourcing file -
    called on line 1 of file ~/.config/fish/config.fish

from sourcing file ~/.config/fish/config.fish
    called during startup

rbenvは、1.1.1だから、そこまで古くないのだけど。。

とりあえず、Issueを見つけたので、以下のように設定を変更して、反映させた。

togattti@dev ~> cat ~/.config/fish/config.fish
if status –is-interactive
  set PATH $HOME/.rbenv/bin $PATH
  . (rbenv init - | psub)
end

参考

. (rbenv init -|psub) breaks fish shell executable files · Issue #501 · rbenv/rbenv · GitHub