Skip to content

Instantly share code, notes, and snippets.

@dokimyj
Created December 31, 2021 07:48
Show Gist options
  • Save dokimyj/7a1db3f2e2718c91ea2d1e661c148c3c to your computer and use it in GitHub Desktop.
Save dokimyj/7a1db3f2e2718c91ea2d1e661c148c3c to your computer and use it in GitHub Desktop.
Novice Trick & Tips for Mac, Linux, UNIX, K8s, Docker, Ruby, Shellscripts, etc

Dockers

基本 docker コマンド

  • Docker で実行中のコンテナーのリストを取得: docker ps
    • 既に中断された docker も見せる: docker ps -a
  • Docker 実行・停止: docker run <イメージ名> / docker stop <イメージ名>
  • コンテナーを削除: docker rm <イメージ名>
  • ローカルに残ってるイメージリスト: docker images
  • ローカルのイメージ自体を削除: docker rmi <イメージ名>
  • ローカルにイメージをダウンロードのみする: docker pull <イメージ名>
  • 実行中のコンテナーのログを見る: docker logs <コンテナー�ID>
  • ローカルで持っているイメージ・実行中のコンテナーの設定を確認したい: docker inspect <イメージ名・コンテナーID>

docker run応用

  • イメージに特定のコマンドを適用させて実行: docker run <イメージ> <コマンド>
  • 実行中のコンテナーでコマンドを一度だけ実行: docker exec <コンテナーID> <コマンド>
  • docker をバッググラウンドで実行: docker run -d <イメージ>
  • イメージ実行後に stdin でコマンドを入力: docker run -it <イメージ>
    • -i だけでは stdin を打つターミナルがないため、必ず -it
  • 特定ポートで、コンテナー外から docker へ接続させる: docker -p <ローカルポート>:<コンテナーで認識するポート> <イメージ>
  • docker のボリュームをコンテナー外に指定する: docker run -v <実際のパス>:<イメージ内認識するパス> <イメージ名>
  • 特定環境変数を指定して docker を実行させたい: docker run -e <環境変数> <イメージ>

Dockerize

  • Dockerize は一連のコマンドやイメージプールにより、docker run を自動化すること
  • Dockerfile の要素
    • FROM: ベースになる OS またはイメージ (必須)
    • RUN: FROM の OS で実行させたいコマンドを実行
    • COPY: ローカルのファイルをコンテナー側に cp -r
    • WORKDIR: cd
    • COMMAND: イメージの最後に特定のコマンドを実行させる
    • ENTRYPOINT: docker run <イメージ名> $1 から $1 を args として認識
      • CMD との違い: 後ろに $1 が必須になる
      • ENTRYPOINT sleep に 5秒 デフォルト値をあげたい: ENTRYPOINT ['sleep'] \n CMD ['5']
      • 注意1: ENTRYPOINT のデフォルト値として CMD を使う際、必ず両方 [<コマンド・アーギュメント>] として
      • 注意2: docker run --entrypoint でアーギュメントを書き換えると CMD 定義やイメージ名後の値は無視
    • EXPOSE: 特定ポートを開く
  • Dockerfile の作成が終わったら docker build . -t <イメージ名> でイメージ生成
  • ↑で作られたイメージを Docker Hub にプッシュ: docker push <作られたイメージ名>
    • 何も指定しない場合、デフォルト docker hub にプッシュするようになってしまう
    • つまり、docker build . -t の後に着く正しいイメージタグ指定は <個人 Hub 名>/<イメージ名>

Docker-compose

  • docker ホームページから docker-compose を別設置する必要がある
  • YAMLを利用しよう: docker-compose.yml に集約された docker の設定
  • docker-compose を実行: docker-compose.yml があるところで docker-compose up
  • なぜ compose?: 各アプリを docker run --link で互い相関させる必要がある
    • しないと、docker 間の連結ができなく、動かなくなってしまう
    • しかも、--linkdeprecation 警告がついてくる(削除予定)
  • docker-compose バージョン別特徴
    • version 1
      • 各 name 別の設定がバラバラ
      • 全部一筋の Default Bridge に上げ、docker 間をリンクする
    • version 2
      • service 単位の下に記載(encapsulation)
      • 自動的に Dedicated Bridge network を作り、そこにあげてアプリ名で自動リンク(links 不要)
      • depends on 機能: 起動順番を指定できる(depends_on: )
    • version 3
      • docker swarm/docker stack サポート
      • 全部同じレイヤーに入っているので、link などの定義がいらない
      • environment など環境変数が使える(screwdriver.yaml のように)
  • docker-compose.yml の例 # ##

Version 1

redis:
  image: redis
db:
  image: postgres:9.4
vote:
  image: voting-app
  # イメージの場合
  build: ./vote
  # ./vote 配下の Dockerfile からビルドする場合
  ports:
    - 5000:80
  links:
    - redis
result:
  image: result-app
  ports:
    - 5001:80
  links:
    - db
worker:
  image: worker
  links:
    - db
    - redis

Version 2

version: '2' #2以上は必ず表記
services:
  redis:
    image: redis
  db:
    image: postgres:9.4
  vote:
    image: voting-app
    # イメージの場合
    build: ./vote
    # ./vote 配下の Dockerfile からビルドする場合
    depends_on:
      - redis:
  result:
    image: result-app
    depends_on:
      - db
  worker:
    image: worker
    depends_on:
      - db
      - redis

Version 3

version: '3' #2以上は必ず表記
services:
  redis:
    image: redis
  db:
    image: postgres:9.4
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
  vote:
    image: voting-app
    ports:
      - 5000:80
  result:
    image: result-app
  worker:
    image: worker
    ports:
      - 5001:80
  • Docker Compose のネットワーク (Version 2の例から)
version: 2
services:
  redis:
    image: redis
    networks:
      - backend
  db:
    image: postgres:9.4
    networks:
      - backend
  vote:
    image: voting-app
    # イメージの場合
    build: ./vote
    # ./vote 配下の Dockerfile からビルドする場合
    depends_on:
      - redis:
    networks:
      - frontend
      - backend
  result:
    image: result-app
    depends_on:
      - db
    networks:
      - frontend
      - backend
  worker:
    image: worker
    depends_on:
      - db
      - redis
    networks:
      - backend

networks:
  frontend:
  backend:

Docker Registry

  • Docker イメージのクラウドプラットフォーム
  • つまり、Docker イメージの集大成
  • docker run nginx からの nginx が抱いているのは
    • nginx とは、実は docker.io/nginx/nginx
    • 最初の docker.io/ がない場合、docker コマンドは docker.io/ を推論してから動く
    • 二つ目の / がない場合、docker コマンドは / の前後が同じであることで推論して動く
    • <registry>/<org>/<image> の仕組みが正式名称
  • プライベート Docker Registry に接続するには docker login <registry address> が必要
  • プライベートレジストリを立てる方法
    • docker run -d -p <公開されるポート>:<内部ポート> --name registry registry:2
    • docker image tag <イメージ名> <アドレス>:<ポート>/<イメージ名>
    • docker push <アドレス>:<ポート>/<上記の tag 名>

Docker Engine

  • Linux に Docker を設置する際、実は以下の三つが設置される
    • Docker CLI: コマンドライン、REST を利用し Docker Daemon と疎通
    • REST API: Daemon との疎通・各種案内を出す (利用し、自前のツールも作れる)
    • Docker Daemon: バッググラウンドプロセス
  • -H= オプションでリモート Docker Engine を実行できる
    • ex) docker -H=10.123.2.1:2375 run nginx で 10.123.2.1:2375 の Docker Engine で nginx を実行
  • Containerization: 基本 Docker は namespace に基づいてコンテナー間を区切ってる

Docker のプロセス

  • 普段プロセス ID はユニーク ID
  • なのになんで動作中のコンテナーは Docker が基づいているシステムと同じ番号を?
  • ↑の秘密は namespace: ネームスペースで区切られているため、ps aux で見るとそれなり別の PID を持ってる
  • cgroups
    • 原論的に、Docker のシステムリソース制限はない
    • つまり、Docker が設置されているシステムが Docker にハマってしまう可能性
    • だから docker run --cpus=<CPU占有率> (--memory=<RAM容量>) <イメージ> で制限する
    • 詳細は Docker 公式ドキュメントで
  • Detached Container のプロセスリストを見る: docker exec <Container ID> ps -eaf

Docker のストレージ使い #詳細

  • Docker が設置されたら、/var/lib/docker 配下に Docker 実行に必要なファイルが保存される
  • Docker から作られたボーリュむは /var/lib/docker/volumes に置かれる
  • Layered Architecture
    • Docker イメージはベースから設置・コマンドの「レイヤー」を重ねて作られる
    • Layer にすると、既存のイメージから変更された部分だけ新しい Layer として扱えばいいので、かかる時間が短縮
    • こうやって作られたイメージの中身は全部 Readonly で、修正不可(修正したら新たにイメージビルド)
  • Copy-on-write
    • イメージのファイルは原則 Readonly だが、修正絶対できない?
    • そうでもない。ただ、Container で実行される時にコピペして持ってきてから修正する。
    • ↑で修正・追記される事項は実は /var/lib/docker/volumes 配下に保存される
  • volumes
    • って、コンテナーで実行されて何かを記録したりする行動は「Volume」で行われる
    • コンテナーの Volume は我らがコンテナーを潰すと飛んでいってしまう
    • が、docker run -v オプションで VolumeMounting ができる
    • bind mounting: 逆に、既存のデータを使いたい場合も、↑の docker run -v を使い、/var/lib/docker/volumes の如く引き継げる
  • Volume Mount と Bind Mount の違い

Volume mounting

$ docker volume create data_volume # volume をあらかじめ作っておく

$ docker run -v data_volume:/var/lib/mysql mysql # 一行目で作った Volume に紐づけて MySQL イメージ駆動の際、データを保存

Bind mounting

$ find -name 'mysql' / # '/' 配下どこに mysql があるか確認
/data/mysql

$ docker run -v /data/mysql:/var/lib/mysql mysql # ↑の Docker 外のデータを Docker で引き継ぐ
  • -v は Deprecate 寸前、今後は --mount type=<bind/volume>,source=<path>,target=<dockerwise path>
  • さあ、なら何で Docker はこのストレージを管理するの?
    • Storage Driver: AUFS, ZFS, BTRFS, Device Mapper, Overlay, Overlay 2 など
    • OS により使えるドライバが異なる
  • 設置されている docker のいろんな情報を見るためのコマンド: docker info
  • 特定イメージの履歴を見るコマンド: docker history <イメージハッシュ>
  • docker の中身がどの形でディスクを使っているか: docker system dh (-v for verbose)

Docker Networking

  • Bridge: Default network for docker, 各コンテナーを紐づく一筋の内部 IP
  • none: --network=none で設定する、ネットワーク切りの状態
  • host: --network=host で設定する外部への単一出入り口(1ポート1アプリ)
  • ネットワークカスタマイズ
$ docker network create \
--driver bridge \ # ブリッジを利用
--subnet 182.18.0.0/16 \
custom-isolated-network # 最後は決めたいネットワーク名を入力
  • Docker のネットワークリストを確認: docker network ls
  • コンテナー間連結に IP を使うのは危うい: コンテナーの hostname を使おう!
    • Docker の DNS サーバー IP: 172.0.0.11

Container Orchestration

  • コンテナーオーケストレーション: Docker が実行されているコンテナー自体を多重化
  • コンテナー間通信: Auto-Scaling により、コンテナー内の Docker 1つごとに互いのリンク docker を向かう
  • 種類: Docker Swarm(Docker), kubernetes(Google), MESOS(Apache) など
  • Docker Swarm の実行方法
    1. Swarm Manager: docker swarm init / Node Workers: docker swarm join --token=<init で生成されたトークン>
    2. Swarm Manager: docker service create --replicas=<ノードワーカ数> <イメージ>
  • Kubernetes 自体のコースが必要だから、それ聞いてね
    • 基本コマンド: kubectl run --replicas=<ノードワーカ数> <コンテナー名>
    • ローリングアップデート: kubectl rolling-update <コンテナー名> --image=<アップするイメージ>
    • ↑をロールバック: kubectl rolling-update <コンテナー名> --rollback
  • kube の基本構造
    • コンポーネント: k8s の体系を管理するアプリ
    • ノード: kubernetes の基本単位
    • クラスタ: ノードの束
    • マスタ: ノードの状態を監視する
  • kubectl
    • k8s の核心コマンド
    • docker service みたいなことだね

Docker-compose で FE-API-DB を立てる際当たった問題

  • 社内 Git は Docker で clone などできないよ
  • イメージ作りに時間かかるから docker-compose.yml にイメージの代わりに build: を定義
  • ローカル開発の確認用のため、docker-registry にイメージを作るのは ×
  • DB からのつなぎができない場合
    • 一旦 DB のイメージを docker run した状態で <ユーザー名> でログインできるか確認
    • できたら設定の誤りをひとまず確認
    • なかったら init.sql を用意 (内容: ユーザー、データベース、権限などの生成)
    • docker-compose.yml の db(mysql) コンテナー定義に command: として init.sql を実行

その他

Git コマンド

正規表現

  • 1桁以上の数字チェック(decimal): /\d+/
  • 1桁の数字チェック: /\d/ or /[0-9]/

Jenkins!

  • ERROR: Couldn't find any revision to build

    • ジョブの設定でソースコード管理の Git URL 記載部分にある「高度な設定」を押して開く
    • 名称に「origin」
    • Refspec に +refs/pull/*:refs/remotes/origin/pr/*
    • ブランチ指定は空欄にしておく
  • jenkins-cli jar ファイルの使い方: java -jar <jenkins-cli.jarのパス> -auth jenkins:<パスワード> -s <Jenkins URL> <コマンドなど>

    • 確認できたコマンド: get-job, update-job, get-node, update-node
    • アップデート注意点: 必ず適用する xml ファイルを cat してから (ex: update-node なら cat mac-setting.xml | java -jar ~ update-node <設定するつもりの Mac IP>)

Python

mapobj = {}
mapobj['keyname'] = VALUE
with open(FILEPATH, 'r') as input_file:
  for line in input_file:
    do_something(line)

Android SDK/NDK

  • NDK バンドルの設置: $ANDROID_HOME/sdk/tools/bin/sdkmanager ndk-bundle
  • 設置されている NDK バンドルのバージョン確認: $ANDROID_HOME/sdk/ndk-bundle/source.properties に書かれている
  • Gradle 5 のバグ: 一部 mvn/jcenter pom 認識に失敗
  • Gradle ファイルで標準出力を放たす

Javascripts(Node, Vue, Moment, mocha, etc...)

"resolutions": {
  "<バージョンを強制するモジュール>": "<強制するバージョン>"
}

MySQL

mysqldump -u <ユーザー> -p <パスワード> <DB名> <テーブル名1> <テーブル名2> ... --master-data --single-transaction > hogehoge.dump

iOS

Android

  • Build Tool 31 の仕様変更に対処: BUILD_TOOL_PATH=$ANDROID_HOME/build-tools/31.0.0; cp $BUILD_TOOL_PATH/d8 $BUILD_TOOL_PAH/dx; cp $BUILD_TOOL_PATH/lib/d8.jar $BUILD_TOOL_PATH/lib/dx.jar

kubernetes

k8sの構造

  • Node
    • k8s が設置されているマシン(物理、論理いずれも)
    • コンテナーが走る所、旧名は「minions」
    • これが落ちたら中のアプリケーションも落ちる
  • Cluster
    • 2個以上の Node を組み合わせた Node 束
    • 冗長化+ロードバランシング
  • Master
    • Cluster/Node の Failover やロードバランスなどコントロール
  • k8s のコンポーネント: 我らが k8s を設置したら実際設置されるもの
    • k8s API
    • etcd keystore
    • kubelet service (node 毎に走ってる監視エージェント)
    • container runtime (Docker など)
    • controller
    • scheduler
  • master と worker の違い
    • worker は Docker Container Runtime / kubelet(exporter) 抱合
    • master は kube API server, etcd keystore, control manager, scheduler 抱合
  • kubectl
    • Application deployer/manager

Pods とは

  • k8sはコンテナーに直接ノードを設置しない
    • Pods という単位で配布
    • 一つのノードの中に pods を設置し、多重使用者に対応
    • スケールアウトのために、別ノードをたてて、そこに pods 追加
  • Multi-container Pods
    • 他のアプリ(集計など)を同時に同じ Pod に設置も可能
    • 原理   - docker run で複数のイメージを回す
      • -link で先の複数のコンテナーを補助する
    • Pod は↑の原理で、各 Pod として結んでくる形
  • kubectl の概念
    • kubectl run: ノードを立てて、中に Pods を作り、イメージ回す
    • kubectl get pods: デプロイされた pods のリストを確認
    • ユーザーから pods への直接的な接続は不可
    • ユーザーへの提供は後で
  • kubectl コマンドの用例
    • kubectl run <名前> --image=<利用したいイメージ>: イメージの名前が一致しない・イメージが Docker hub 似ない
    • kubectl get pods: pod のリスト取得
      • kubectl get pods -o wide: IP など追加情報を見せる
    • kubectl describe pod <pod 名>: pod の状態、設定などを説明
      • events 項目: 実行時の記録、各コンテナーの生成された状態などを表示

k8s での YAML のやりとり

  • k8s の YAML はいつも以下の 4項目が入ってる
    • apiVersion
    • kind
    • metadata
    • spec
  • apiVersion と kind
    • k8s でこの YAML をどの設定で、どのバージョンで使うか定義
    • 使える設定例: POD-v1, Service-v1, ReplicaSet-apps/v1, Deployment-apps/v1
  • metadata
    • 配布したい pod の名前、イメージ、アプリレーベル
    • dictionary オブジェクト基盤
    • 他は「追記ダメ」な属性だが、labels には自由につけれる
  • spec
    • k8s に追加情報として色々入れるパート
    • dictionary オブジェクト基盤
    • containers
      • dictionary 型 array で複数のコンテナーを定義
  • 作成後に確認する方法
    • kubectl describe pod <pod名>

Replication Controller と ReplicaSet

  • 共通概念
    • 複数の pods をコントロールする管理者だが、一つも管理できる
    • ユーザーの数が増えたらノードを追加し、同じ Pod を複製することまでできる
  • Replication controller
apiVersion: v1
kind: ReplicationController
metadata:
  name: myapp-rc
  labels:
    app: myapp
    type: frontend
spec:
  template: # この配下は pod の metadata/spec を完結して書く
    metadata:
    spec:
  replicas: 3 # 複製する数

上記の YAML を kubectl apply したら以下のコマンドで確認可能 kubectl get replicationcontroller

  • ReplicaSet
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: myapp-rs
  labels:
    app: myapp
    type: frontend
spec:
  template:
    metadata:
  replicas: 3
  selector: # Replication Controller との大きな違い, 省略可能
    matchLabels: # labels にてコントロール対象軍を指定
      type: frontend

selector はコントロール対象を指定する枠、 本 replicaset で作られなかった pods もコントロールできる 上記の YAML を kubectl apply したら以下のコマンドで状況確認 kubectl get replicaset

  • labels と selectors
    • 基本、replicaset は Pods を監視するプロセス
    • だが、どうやって監視対象がわかる?: だから matchlabels
    • ↑監視中に死んだ pods を蘇るために、spec-template は必須
  • replicaset などの replicas オプションの適用方法
      1. replicas の数字を修正し、kubectl replace -f <yaml> で適用
      1. kubectl scale --replicas=<数字> -f <yaml> で適用 *既に配布されている YAML 系の設定を書き換えるには: kubectl edit <kind> <指定した名前>

Deployment

  • 複数 Deployment に望むこと
    • 同時に複数の同じインスタンスが動くこと
    • アップデートは時差を置いて、順番に(Rolling Update)
    • 途中で失敗したらすぐロールバックできる
    • 実際アップデートの適用は全インスタンス同時にできる(Pause&Update)
  • デプロイ用 manifest の様子
apiVersion: apps/v1
kind: Deployment
metadata:
  name: <デプロイ名>
  labels:
    app: <アプリラベル>
    type: <タイプクラスラベル>
    ...
  • Deployment マニフェストからデプロイが作られた際の作られるもの(kubectl get ~~ で確認)
    • deployments
    • replicaset
    • pods
  • Deployment と Replicaset は「成果物」としては特に差がなさそう
  • yaml なしで、kubectl コマンドで即時 Deployment を作ってみ!
kubectl create deployment <デプロイ名> --image=<使うイメージ名>
kubectl scale deployment --replicas=<作りたいレプリカ数> <デプロイ名>
  • アップデートとロールバック
    • 何かを Rolling Update する際、k8s では自動的に Rev を作って前の奴を保存する(rollback用)
    • kubectl rollout status deployment/<デプロイ名> で確認できる
  • デプロイ戦略の種類
    • Recreate: 以前バージョンを全部壊し、新しいデプロイへ切り替え(合間にダウンタイム発生)
    • Rolling Update(基本): 一個ずつ新しいデプロイに切り替える(ダウンタイムなし)
  • ↑戦略実行の方法
    • kubectl apply -f <修正した yaml ファイル>
    • kubectl set <spec 配下の設定> deployment/<デプロイ名> <コンテナー名>=<イメージ名>:<タグ>
    • kubectl edit deployment <デプロイ名>
    • ただし、2/3番目の方法は yaml ファイルが変更されるわけではないので注意!
  • Rollback のやり方
    • kubectl rollout undo deployment/<デプロイ名>
    • どうなっているかは kubectl get replicaset により確認可能
  • kubectl rollout Tips
    • --record: create, edit, set などのコマンドにつけると、kubectl rollout history deployment/<デプロイ名> で追跡できる
    • 注意: rollout history は完全に同じ履歴が発生すると(rollout undo等)上書きされ、古りリビジョンは消える

Networking

  • k8s 内部の IP は pod ごとに分配されるため、pod 間通信は内部 IP でできる
  • だが、pod はいつでも recreate/destroy できるので IP 直接通信はよくない
    • 例えば、k8s クラスタ内に複数の node がある場合、node の各 pod は同じ内部 IP を保つため、衝突になる
    • 結局 NAT 設定が必要となる
    • Cisco FCI, Psyllium, flannel, weavenet などのソルションで解決はできる
    • 上記のソリューションは NAT ルーティングをしてくれる

Services

  • k8s の様々なサービスを繋ぐ技術
  • node の pod にアクセスする方法
    • node に SSH 接続し、直接該当 pod の IP を叩く
    • node 自体に接続しても可能だが、それは Service のおかげ
  • Service(Port Service) の種類
    • NodePort: node 自体のポートを解放し、内の全ての pods を外部から接続できるように
    • ClusterIP: クラスタ内の特定 Pod 束と node を紐づく
    • Load Balancer: node に複数のエンドポイントを pod と紐付き、外部からは一筋で通じるように
NodePort
  • NodePort の構成
    • Targetport: pod が動いているポート
    • Serviceport(port): service が pod と紐づかれているポート
    • NodePort: service にて開放されている node のポート
  • NodePort service の設定方法
apiVersion: v1
kind: Service
metadata:
  name: myapp-service
spec:
  type: NodePort
  ports:
    - targetPort: <pod 自体のポート>
      port: <service のポート> ←必須
      nodePort: <外部に解放するポート>
  selector: ← "front-end" pod のラベルを持ってくる
    app: myapp
    type: front-end
  • 確認方法: kubectl get services → TYPE: NodePort を確認
  • 同じサービス用 pod が複数あったら: labels を同じくすれば良い
  • ↑で pod ではなく node が複数: service は node を横断し作られるため、同じ NodePort で設定される
  • ブラウザで接続確認する URL を得る: minikube service <ポートサービス名> --url
ClusterIP
  • 一般的なウェブサービスの構成: Frontend - Backend - DB
    • 3階層各々に Pods が建てられ、その Pod は各自の内部 IP を割り当てられる
    • 階層間の通信に IP を使用するのは不適切 → 階層内(クラスタを跨ぐ)を一つに結ぶサービスを作る
  • ClusterIP の設定方法
apiVersion: v1
kind: Service
metadata:
  name: back-end
spec:
  type: ClusterIP
  ports:
    - targetPort: <各 node が向かうポート>
      port: <階層間の通信ポート>
  selector: ← "back-end" の pod ラベルを持ってくる
    app: myapp
    type: back-end
  • 確認方法は NodePort と同じ (TYPE: ClusterIP を確認)
Load Balancer
  • 複数のフロントエンドサービスが存在する場合、どうやって切り分けるか?
    • ロードバランサー役割の新たなサービスを k8s で立てる
    • GCP, AWS, Azure などのクラウドプラットフォームサービスの native LB 機能を使う
  • 設定方法: NodePort と基本設定は同じで、spec.type だけ LoadBalancer にする
    • ただし、この機能は k8s が基づいたプラットフォームが LB 機能をサポートするのが必須

Microservices Architecture

  • GCP などで Docker/k8s 技術を利用する Web サービスを作る基礎: Microservice 概念
  • 例: Voting-app
    • Voting-app: nodejs
    • in-memory DB: redis
    • worker: Dotnet
    • db: Postgres
    • result-app: nodejs
Case 1. 各アプリを Docker で一つずつ立てるなら
  • 各イメージがローカルにある前提で、普通に docker run
    • docker run -d --name=redis redis
    • docker run -d --name=db postgres:9.4
    • docker run -d --name=vote -p 5000:80 voting-app
    • docker run -d --name=result -p 5001:80 result-app
    • docker run -d --name=worker worker
  • ↑の5コマンドでは Internal Server Error...
    • なので docker run --links を使うべき (繋がりのある DB への --link を「アプリ」に)
    • voting-app は redis, result-app は db, worker は両方の DB へ
Case 2. k8s でデプロイ
  • AC
    • 各コンテナーをデプロイされる
    • コンテナー間通信ができている
    • 外部から View アプリへのアクセスができる
  • 手順
    • pods からデプロイ
    • どのアプリがどこに露出されるべきかを把握
    • ↑により適切なサービスを立ち上げる(内部公開=ClusterIP, 外部アクセス=NodePort) *worker は外部や他の pods から worker に向かうユーズケースがないため、サービスを設定しない
manifest.yml で env 入れる方法
...
spec:
  containers:
    - name:
      image:
      ports:
        - containerPort:
これ→ env:
        - name: <環境変数名1>
          value: <環境変数値1>
        - name: <環境変数名2>
          value: <環境変数名2>
...
kubectl get は重なって使われる

kubectl get pods,svc,rs,...kubectl get all せず、みたいもの選べる

deployments
  • 各アプリを必要な数の分の Replica を作ってくれる
apiVersion: apps/v1
kind: Deployment
metadata:
  name: voting-app-deploy
  labels:
    name: voting-app-deploy
    app: demo-voting-app
  spec:
    replicas: <複製の数>
    selector:
      matchLabels:
        name: voting-app-deploy
        app: demo-voting-app
    template:
      (pod を作る際に書いた yaml から apiVersion と kind を除く全てをコピペ)

k8s on Cloud Platforms (Introduction only)

  • k8s on Cloud Platform の種類
    • ↓ 簡単な使い方のみ(詳細設定や仕業は各プラットフォームより講義を受講すべき)
    • Turnkey(Self-hosted): 直接 VM とデプロイスクリプトを管理 (ex: AWS w/ kops/KubeOne)
    • Managed(Hosted): CaaS, VM や K8s が設置されている (ex: Google Container Engine)
    • ↑いずれも基本「node」を作ってから、deployment/service の手動デプロイに基づく k8s 制御
  • k8s on GCP(Google K8s Engine)
    • Web UI から OS, k8s バージョン, 地域設定などを行う
    • Cloud Shell も Web UI に含まれている
    • 基本「LB サービス」がデプロイされているため、サービスを LB にする
  • k8s on AWS(Elastic K8s Service)
    • AWS CLI, kubectl が必須
    • VPC を直接セッティング可能(Cluster 単位)
    • SSH が欲しかったらセキュアキーを要請するのも可能
    • Scaling まで Web UI で完結できる
    • ターミナルはローカルのを使い、~/.kube に設定が刻まれる
    • GKE と同じく、LB が基本実装されているため、サービスを LB にする
    • kubectl get svc に表示された External IP が接続できる�URL になっている
  • k8s on Azure(Azure K8s Service)
    • Service Principal: クラスタにくっついて様々な設定できるアクセス権限を与える
    • リソースをデプロイ→Web UI でアクセス→Cloud Shell にて
    • 作られた node に deployment/service をデプロイ

Kubeadm を利用する Multi Node Cluster

  • kube admin tool: multi node cluster 用の admin tools
  • kube master は kube-apiserver, etcd, node-controller, replica-controller, サーバー証明書などを管理
  • kubeadm を利用する multi node cluster 構築手順(概念)
    • クラスタの設定が跨ぐ「複数システム」または VM を用意
    • Node を master と worker で割り当てる
    • 各 node にコンテナーランタイムを設置(Docker)
    • kubeadm tool を全ノードに設置
    • master server node を初期化
    • pod network という特殊なネット設定を行う
    • worker node に join node を設置し、master node と紐づく
  • 実際手順
    • lsmod | grep br_netfilter で既存の動いている kubeadm がないか確認
    • なければ各 node に sudo modprobe br_netfilter で probe を実行
    • iptables, ip6tables のブリッジを k8s 設定ファイルに書き込む(sudo tee /etc/sysctl.d/k8s.conf)
    • 各ノードに docker(daemon, docker 本体、containerd, CRI-O など) と kubeadm, kubelet, kubectl を設置
    • master node でAPI サーバーの IP を設定
      • kubeadm init --pod-network-cidr <pod network 内で使う IP の default gateway>/16 --apiserver-advertise-address=<master IP>
    • 上記設定の終わり目に表示される To start using your cluster~ の下の3行を Root ではないユーザーとして実行
    • 以下のコマンドで master の pod network addon インストール後に worker node を Join させるコマンドを用意
      • kubeadm join <master node IP>:6443 --token <master 設定時に出たトークン> --discovery-token-ca-cert-hash <証明書解読用 Hash>
    • kubernetes.io の kubeadm 設定にある「pod network 設定」の kubectl apply -f <設定ファイルまたはファイルのURL>... を実行

Linux 系

// Package.swift
products: [
        .executable(name: "anz", targets: ["anz"])
    ],
$ sudo yum install yum-plugin-versionlock # yum-plugin-versionlock 設置

$ yum list <パッケージ名> # パッケージのバージョンリストを確認

$ sudo yum install <リストコマンドで確認したバージョン指定ありのパッケージ>

$ sudo yum versionlock add <パッケージ名> # バージョンを固定したいパッケージを設定
$ cat > /etc/apt/preferences.d <<EOF
Package: <パッケージ名の先頭>-*
Pin: version <固定したいバージョンより一つ上>-*
Pin-Priority: -1 # このバージョンにあげるな、ということ
EOL

$ sudo apt-get update

もしくは

$ cat > /etc/apt/preferences.d <<EOF
Package: <パッケージ名の先頭>-*
Pin: version <固定したいバージョン>-*
Pin-Priority: 1001 # このバージョンが最優先、ということ
EOL

$ sudo apt-get update
  • Linux(CentOS) で nameserver を簡単に確認: systemd-resolve --status

Mac OS

  • dscl コマンドの使い方

    • 照会:dscl . -list /Users DataToCheck
    • 修正:dscl . -change /Users/UserToChange DataToChange OrigData NewData
    • 作成:dscl . -create /Users/NewUser
    • 追記:dscl . -create /Users/UserName DataToInsert NewData
    • パスワード変更:dscl . -passwd /Users/UserToChange OldPass NewPass
    • 削除:dscl . -delete /Users/UserToDelete + rm -rf <HomeDirectoryPath>
  • VNC 権限付与: sudo /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -activate -configure -access -on -clientopts -setvnclegacy -vnclegacy yes -restart -agent -privs -all

  • .podspecを探すルートを変えたい

    • .podspec に s.xcconfig = { 'USER_HEADER_SEARCH_PATHS' => '"${PROJECT_DIR}/.."' } を追記
    • 特定パス配下全部: s.xcconfig = { 'USER_HEADER_SEARCH_PATHS' => '"${PROJECT_DIR}/.."/**' }
  • json gem 設置中 'mkmf.rb can't find header files for ruby' エラーが発生したら

$ sudo xcode-select --reset
$ ruby -rrbconfig -e 'puts RbConfig::CONFIG["rubyhdrdir"]'
  • Applescript Editor 書き方 Tips
    1. "システム環境設定"の "com.apple.preference.security" パネルの "プライバシー"タブの "フルディスクアクセス" アンカを activate して一番前に持ってくる
tell application "System Preferences"
	reveal anchor "Privacy_AllFiles" of pane id "com.apple.preference.security"
	activate
end tell
  1. 一番 前の windowの 全ての要素を uiElems に set
tell application "System Events"
	tell every window of (every application process whose frontmost is true)
		set uiElems to entire contents
	end tell
end tell
  1. consoleに指定したオブジェクト上の全てのコンテンツの情報を出力: uiElems

*もしくは以下の方法が使える

tell application "System Events" to tell process "<name of the process>"
  get attributes of every UI element of window 1
end tell
xcrun simctl push <device> com.example.my-app ExamplePush.apns
import UserNotifications
  • brew formula 作成例
require 'formula'
class Hoge < Formula
  desc "Hoge"
  homepage "https://github.com/dokimyj/hoge"
  url "https://github.com/dokimyj/Hoge.git", :revision => "agjidsjgpghiapecommithash6437374"
  # version '1.0' <- if needed
  def install
    system "make", "install", "PREFIX=#{prefix}"
  end
end

Ruby

  • Ruby で使える Shell コマンド

    • Fileutils.cp_r = cp -r
    • Fileutils.mkdir_p = mkdir path
    • Dir.glob = ls | grep or find(Mac)
  • File

    • ファイルを新たに作りたい: File.write(<ファイルパス>, <ファイル内容>)
      • ファイルの後ろに追記したい(>>) ならば: File.write(<ファイルます>, <追記したい内容>, mode: 'a')
    • パス剥がしたファイルネームのみ表示: File.basename(path)
    • cat | grep を ruby で: File.open('ファイルパス').grep(/正規表現/)
  • String

  • Array

    • 配列のnested状態を全部解除(平坦化): Array.flatten
    • 配列のelementsで重複している値を削除: Array.uniq
    • 配列の一列化: Array.join(delimeter)
    • 配列の特定indexまで切り取って前の部分捨てる: Array.drop(idx)
  • net/http

  • .map 使い例

Array.map! do |処理対象|
    処理内容
    処理対象の書き換え
end

ruby-1.9.2-p0 > arr = ["This is some sample text", "text file"]  
 => ["This is some sample text", "text file"]

ruby-1.9.2-p0 > arr = arr.map {|s| s.gsub(/text/, 'document')}
 => ["This is some sample document", "document file"]
  • Ruby の例外処理

    • 一般1: (begin-)rescue-(raise-ensure-)end
    • 一般2: (begin-)throw-catch-(ensure-)end
    • ensureを使う場合、必ず begin で始まる
  • Shell の標準出力(STDOUT/STDERR) を Capture する

    • 標準出力($stdout)をコピーし、StringIO に入れる
    • 臨時処理が終了されたら元の $stdout を戻す
    • もしくは system(echo hoge >/dev/null 2>&1) などで省略
def with_captured_stdout
  original_stdout = $stdout  # capture previous value of $stdout
  $stdout = StringIO.new     # assign a string buffer to $stdout
  yield                      # perform the body of the user code
  $stdout.string             # return the contents of the string buffer
ensure
  $stdout = original_stdout  # restore $stdout to its previous value
end
  • IO.reopen
    • IO#reopen を使って、block なしでも標準出力向き先変更
orig = $stdout.dup
$stdout.reopen("output.log", "a")

puts "Ruby"
puts "Java"

# 標準出力は抑えられ、output.log に残る

$stdout = orig.dup

puts "Python" # 標準出力で "Python"
  • yield とは

    • 特定のメソッドを動かして、その影響範囲の中で別の関数を処理
  • sort byArray.sort_by { |x| <条件> ? 0 : 1 }

  • ruby hashmap

ary = ['hoge', 'fuga', 'foo', 'bar', 'baz', 'bad']
puts Hash[*ary]
=> {hoge => 'fuga', foo => 'bar', baz => 'bad'}
starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
# 何か時間かかるタスク・プロセス
ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
elapsed = ending - starting
elapsed # => 9.183449000120163 seconds
  • ruby でウェブサーバーを開く: ruby -run -e httpd -- --port <ポート番号>

    • 特定ポートが開かれているか確認1: telnet <IP/hostname> <ポート番号>
    • 特定ポートが開かれているか確認2: nc <IP/hostname> <ポート番号>
  • ruby には Increment operator(++, --) がない

  • bundler バージョンがシステムではない、brew のバージョンと混在している時の対処

brew uninstall ruby
brew install [email protected]
export PATH=/usr/local/opt/[email protected]:$PATH
sudo rm -rf /usr/local/opt/ruby
sudo ln -s '../Cellar/[email protected]' /usr/local/opt/ruby
sudo chown -R <admin 権限のある垢> /usr/local/opt/ruby

Shellscript

  • sh で >/dev/null >2>&1 の意味は?

    • 標準エラー(stderr, 2)を標準出力(stdout, 1)に
    • 標準出力は /dev/null に、標準エラーも標準出力として表示する
    • つまり、全ての標準画面表示をミュートする
  • 前回のコマンド実行の exit code を確認: echo $?

  • 除きたい文字列を指定し検索: grep -v

  • 文字列で特定文字以降を消したい: 変数に割り当てて ${<変数>%<トークン>*<トークン>*...}

STR='hoge/fuga/piyo'
echo ${STR%/*}
# hoge/fuga
echo ${STR%/*/*}
# hoge
  • Unix Array

    • 基本配列初期化方法: array_name[n]=<value> ...
    • bash での初期化方法: array_name=(value1 ... valuen)
    • 値の出し方: ${array_name[index]}
    • 配列内の全てを見せたい: ${array_name[*]} または ${array_name[@]}
    • 文字列をトークンで split: IFS='<トークン>' read -r -a array <<< "$string"
  • grep 結果を Array に: targets=($(grep -HRl "pattern" .))

  • grep で wildcard 検索

    • grep -o で only-matching を使う:grep -o "\w*/path/to/file/*.*.extension名\w*" で拡張子 File.basename(filename+.extension, .extension) と同じことができる
  • エラーが起きてもスキップしたい: <コマンド>||true

  • sh でファイルをライン毎に読み込んで処理while read -r line; do COMMAND; done < input.file

  • bash script loop

for OUTPUT in $(Linux-Or-Unix-Command-Here)
do
	command1 on $OUTPUT
	command2 on $OUTPUT
	commandN
done
#!/usr/bin/expect
set timeout 10
set password "yomama"
spawn "./chef.sh"
expect "Password:"
send "$password\r";
# 環境変数にある物を使うなら send_user "$env(PASSWORD)\n"
interact

UNIX 共用

  • 特定IPでアクッセスしたい(ドメインに関わらず): /etc/hosts の修正 例)
127.0.0.1 localhost
255.255.255.255 broadcasthost
::1 localhost
xxx.xxx.xxx.xxx hoge.fuga.piyo
cat > /etc/chef/client.rb <<'EOP'
<%= config_content %>
chef_license "accept"
EOP
$ cat << EOF > test.txt
>This
>is
>multiline test
>EOF

$ cat test.txt
This
is
multiline test
# ~/.bashrc
agent="$HOME/.ssh/agent"
if [ -S "$SSH_AUTH_SOCK" ]; then
    case $SSH_AUTH_SOCK in
    /tmp/*/agent.[0-9]*)
        ln -snf "$SSH_AUTH_SOCK" $agent && export SSH_AUTH_SOCK=$agent
    esac
elif [ -S $agent ]; then
    export SSH_AUTH_SOCK=$agent
else
    echo "no ssh-agent"
fi
  • kill -s SIGINT SIGSTOP SIGCONT

    • SIGINT(-9) したら完全 process kill
    • SIGSTOP は一時停止、SIGCONT で復活できる
  • コマンドの実行バイナリを指定したいalias gorgonzola='/usr/local/gorgonzola'

  • disk usageを人が読みやすく表示:df -h

  • Mac と Linux の sed の違い

    • Mac: sed -i '' -e 's/定期表現/正規表現/g' "sedの疑問点2"
    • Linux: sed -i -e 's/定期表現/正規表現/g' "sedの疑問点2"
  • sed で最初登場する特定正規表現のみ書き換えたい

    • Mac: sed -e '1 s/foo/bar/; t' -e '1,// s//bar/' <<<$ "ファイルやテキスト"
    • GNU sed(多分 linux 系): sed -i -e '0, /定期表現/ s/定期表現/正規表現/' ”ファイルやテキスト"
    • 注意: sed -e 'n, ~'s|hoge|fuga| のパイプが使えず、必ず s/hoge/fuga/ の様、スラッシュで正規式を書く
  • trap コマンド

    • trap 'echo hoge' 9 ならコマンドが kill されたら echo hoge を動かすコマンド
    • javaの try~catch~finallyfinally と似てる
    • 詳細は trap -l
  • SSH(port 22) のみ許容されているリモートに別ポートで VNC つなげたい

ssh -XYCgL <適当なポート>:localhost:5900 @

*もしうまくいかない場合は環境のポート番号を変えて試す

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment