mutao.net

いわゆる雑記。

Raspberry Piにdocker-composeをinstall

環境

install

$ wget https://github.com/docker/compose/releases/download/1.25.5/docker-compose-Linux-x86_64
$ mv docker-compose-Linux-x86_64 /usr/local/bin/docker-compose
$ chmod 755 /usr/local/bin/docker-compose

docker-composeでエラー発生。

[dev@localhost drone]$ docker-compose up
-bash: /usr/local/bin/docker-compose: cannot execute binary file: Exec format error

どうやらOSに対応していないバイナリを実行しているのが原因みたい。

RasberryPiのCPUアーキテクチャはARMなのでそれが原因ぽいなぁということでバイナリ探しを始める。

バイナリがないので https://github.com/docker/compose.git をclone。

https://github.com/docker/compose/blob/master/script/build/linux

このscriptを実行する。

https://github.com/docker/compose/pull/6908

このPRを見るとRasberryPiにdocker-composeをinstallする手順が書いてありました。

PRから引用。docker自体は前もってinstall必要です。

Prerequisites

a Raspberry Pi
have Git and Docker installed
How to verify

Login to your Raspberry Pi
git clone https://github.com/docker/compose
cd compose
scripts/build/linux
dist/docker-compose-Linux-armv7l --version

↑の手順ではないですが、git checkout で installしたいバージョンのブランチにします。

https://github.com/docker/compose/tags

## 最新
$ git checkout 1.29.2
## scriptsってPRにあるけどscript配下にありました。
$ ./script/build/linux

## エラーメッセージでるけど無視、PATHが違うだけ、↑のscriptにこのコマンドを実行しているところをコメントアウトしてもいい気がする。
+ mv dist/docker-compose-linux-amd64 dist/docker-compose-Linux-aarch64
mv: 'dist/docker-compose-linux-amd64' を stat できません: No such file or directory

[root@localhost compose]# ll dist/
合計 10492
-rwxr-xr-x 1 root root 10741936  7月  3 09:13 docker-compose-linux-arm64
[root@localhost compose]# ./dist/docker-compose-linux-arm64 --version

## /usr/local/bin/に配置
mv /usr/bin/docker-compose /usr/local/bin/docker-compose

作業後気づいたこと

makefileありました。

https://github.com/docker/compose/blob/master/Makefile

調べたところpipで入れることもできるみたいです。

自宅にラズパイ以外のサーバが欲しくなってきている今日この頃。

GoでMySQL操作入門

MySQL用意

  • Localの環境を汚したくないのでテスト用のDBはDockerで用意する。
  • docker-compose でテスト用のデータを事前に入れておく

github.com

実際にSELECT文を打ってみる

  • 使用するモジュールをgo getで取得
go get github.com/go-sql-driver/mysql

github.com

  • テスト用コード
package main

import (
    "fmt"
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
)

type User struct {
    ID   int
    Name string
}
func main() {
    db, err := sql.Open("mysql", "root:rootpassword@tcp(127.0.0.1:3306)/test")
    if err != nil {
        panic(err.Error())
        fmt.Print("connect failed.")
    }
    defer db.Close()
    fmt.Println("connect complete!")
 
    rows, err := db.Query("SELECT * FROM users")
    if err != nil {
        panic(err.Error())
        fmt.Println("select error occuerd.")
    }
    defer rows.Close()

    for rows.Next() {
        var user User
        err := rows.Scan(&user.ID, &user.Name)
        if err != nil {
            panic(err.Error())
        }
        fmt.Println(user.ID, user.Name)
    }
 
    err = rows.Err()
    if err != nil {
        panic(err.Error())
    }
}
  • エラー発生。
panic: sql: expected 4 destination arguments in Scan, not 2

goroutine 1 [running]:
main.main()
        go-learning/lession.go:51 +0x3f0
exit status 2
  • ぐぐってみると素晴らしいPOST発見

qiita.com

rows.Scanはカラムと一致していないとだめとのこと。

今回用意したテスト用データは以下のような構造をとっているため SELECT * で取得するとカラム数が一致せずエラーが発生する。

`id`, `name`, `register_date`, `update_time`

初歩的なSELECTで躓くのは久しぶりだったのでメモ

負荷

負荷とは

「CPU負荷」と「I/O負荷」に大別される。

CPU負荷( CPUバウンド)

  • プログラムの処理が原因でかかるCPUの負荷のこと
  • 大規模な計算を行うプログラムはディスクとの入出力は行わないが、計算処理はCPUの計算速度に依存する。

I/O負荷(I/Oバウンド)

  • ディスクとの入出力で発生する負荷のこと。
  • 大量のデータから任意のドキュメントを探索するプログラムはCPUではなく、ディスクの速度に依存する。
  • DBサーバはその特性によりCPUの計算速度よりもI/Oに対するインパクトが大きくなる。

psコマンド

$ps aux | head -1 をしているのはヘッダを見たいため。

$ ps aux | head -1 && ps aux | grep httpd
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root        6849  0.0  0.1  44256  6536 ?        Ss    5月30   1:40 /usr/sbin/httpd -DFOREGROUND
www       225430  0.0  0.1  56460  4592 ?        S     6月13   0:00 /usr/sbin/httpd -DFOREGROUND
www       225431  0.0  0.1 2293576 6108 ?        Sl    6月13   1:59 /usr/sbin/httpd -DFOREGROUND
www       225432  0.0  0.1 2490256 6340 ?        Sl    6月13   2:03 /usr/sbin/httpd -DFOREGROUND
www       225433  0.0  0.1 2293576 6140 ?        Sl    6月13   1:59 /usr/sbin/httpd -DFOREGROUND
  • %CPU: psコマンドを実行した際のプロセスのCPU使用率

  • %MEM: プロセスが物理メモリを消費しているかを%で表示

  • VSZ、RSS プロセスが確保している仮想メモリ領域のサイズ、物理メモリのサイズ

  • STAT: プロセスの状態

    STAT 状態 説明
    R (Rum) TASK_RUNNING 実行可能状態。CPUが空きさえすればいつでも実行可能
    S (Sleep) TASK_INTERRUPTED 割り込み可能。入力待ち、スリープ等
    D (Disk Sleep) TASK_UNINTERRUPTIBLE 割り込み不可能。主に短時間で復帰する場合の状態。ディスク入出力待ち
    Z(Zombie) TASK_ZOMBIE ゾンビ状態。子プロセスがexitとして親プロセスにリープされるまでの状態
  • TIME: CPUを使用した時間

楽しい勉強の仕方を考える

目的

  • 自分の市場価値を上げる
  • だけど苦しいのは嫌で、できるだけ楽しく成長したいという典型的な最悪パターンをとっているのが私。
  • 仕事で必要なことはやるが、それにはある程度のゴールがあってプライベートな時間の中で継続的に勉強することができるようにしたい。

勉強とは

① (形動) 努力をして困難に立ち向かうこと。熱心に物事を行なうこと。励むこと。また、そのさま。

コトバンク:

https://kotobank.jp/word/%E5%8B%89%E5%BC%B7-626150

とのこと。前者の「努力をして困難に立ち向かうこと」は目的とは私が考えている勉強とは違う。

優秀な人は困難に立ち向かうことすら楽しめる。が、私は違うし怠け癖がある。

ではどう楽しむか

  • 新しいことができるようになる。
  • 没頭できるようなテーマを考える。
  • 誰かに褒めてもらえる。
  • 仕事で評価され給料があがる。

やってみた

Golangを学んでみる

0からのスタートでGolangを学んでみる。

言語選択理由はtottieさんの書くgopharがかわいかったから。

https://twitter.com/tottie_designer

気軽な理由でも何かを学ぶというきっかけとしては上等な気がする。

何をしたか

A tuor of Goをやって公式documentを見るだけ。

https://go-tour-jp.appspot.com/welcome/1

参考書を買うと「読破して理解する」というタスクが増えるのでやらない。

そもそも「いずれかのプログラミング言語」を初見で学ぶのに参考書がいるか謎。

深く知りたいならテーマを絞って参考書を吟味したい派。きっと怒られる。けど公式documentを見た方がいいと思っている。

versionを間違えればミスリード、果たして全て読んで理解できているかという疑問。

なので、ハンズオン形式にした。

https://github.com/mutao-net/go-lesson1

Githubリポジトリを作成、この時点でREADME.mdを書いた。

記載内容は何をするか簡潔にまとめたもの。

簡潔すぎてフリーダム。

今回の場合は四則演算ができる電卓のようなものを作ること。

失敗

  • 作り込みができるテーマではなかった。
  • もっとGolangの標準モジュールを使ったテーマにすればよかった。
  • そもそも実用性がなく、リポジトリとして管理するには恥ずかしい成果になった。

成功

  • 基礎的な文法をおさらいするにはよかったと思う。

今後について

  • Golangで作られたサービスを調べてサンプルアプリケーションのテーマを作成したい。
  • CRUDを用いるアプリケーションを作成したい。
  • 細部まで拘れるテーマを模索したい。

サーバ/インフラを支える技術

1章 サーバ/インフラ構築入門

本書を読み終えたので軽くメモ。

クラウドが便利になって気にしていなかったところの知識やざっくりとした知識で捉えていたものが理解できるようになる良書だった。

ヘルスチェック

  • ICMP監視(L3)

    echoを投げてリプライが来るか監視する。Webサービスのダウンは検知できない。

  • ポート監視(L4)

    TCPで接続を試みる。Webサービスのダウンは検知できるが、サーバの負荷状態等は考慮できない。

  • サービス監視(L7)

    HTTPでヘルスチェックを試みる。ほとんどの異常を検知できるもののエンドポイントの実装によってはサーバに負荷をかける。

DNSラウンドロビン

1つのドメインに複数のIPアドレスを割り当てて負荷分散を行う仕組みのこと。

サーバの数だけGIPが必要になる。DNSサーバはWebサーバの負荷状態やエラー等の状況に応じて問い合わせ結果をコントロールすることができない。

あくまで負荷分散の仕組みであり、冗長化の仕組みではない。

ロードバランサ

1つのIPに対してのリクエストを複数サーバへ分散させる仕組み。

DNSラウンドロビンではWebサーバ毎にGIPが必要だがロードバランサがリクエストを受け付けるのでGIPは不要。

ロードバランサは複数のWebサーバから1台を選択して処理を中継する。

ヘルスチェックが失敗しているサーバを選択しない。

L4スイッチとL7スイッチ

L4スイッチではTCPで分散先を決定するのに対してL7スイッチはアプリケーションの中身まで解析して分散先を決定する。

L7スイッチではクライアント<->ロードバランサとロードバランサ<->WebサーバでTCPセッションを張る。

L4LBのNAT構成とDSR構成

NAT構成の場合クライアントから届いたパケットの送信先アドレスを書き換えてWebサーバに転送する。

DSR構成の場合はIPアドレスを書き変えずにWebサーバへルーティングする。ロードバランサ側の処理が必要なくなりスループットが向上する。ただしL7での負荷分散を行えないず、SSL終端も行えない。

またWebサーバ側がGIPの処理をする必要があるためVIPの設定が必要になる。

ロードバランサがボトルネックになると考えられる場合はDSR構成が望ましい。

ワンランク上のサーバ/インフラ構築

リバースプロキシ

クライアントからの要求を受け取り、Webサーバへと要求を中継する。このときWebサーバはクライアントではなくリパースプロキシに応答を返す。(WAN -> LAN)

リバースプロキシが存在することにより、クライアントからの要求ごとに適切なWebサーバを選択することができる。(ex. UAで振り分け)

静的コンテンツの場合はAPサーバではなく、別のサーバに振り分けることでメモリ使用率を効率化できる。

本書ではapacheをメインに解説していてnginxの説明はでてきていない。

td-agentを入れてapacheのログ監視をしてみる

td-agentインストール

docs.fluentd.org

curl -L https://toolbelt.treasuredata.com/sh/install-redhat-td-agent4.sh | sh
systemctl start td-agent.service
systemctl status td-agent.service

apacheインストール

# apche起動用ユーザの作成
useradd -s /sbin/nologin www
passwd www

# httpd install
dnf list | grep httpd
dnf -y install httpd httpd-tools httpd-devel httpd-manual

systemctl start httpd
systemctl status httpd
systemctl enable httpd

# firewall設定
firewall-cmd --add-service=http --permanent
firewall-cmd --reload

td-agentの設定

<source>
  @type tail
  path /var/log/httpd/access_log
  format apache2
  pos_file /var/log/td-agent/httpd.access.log.pos
  tag apache2.access
</source>
<match apache2.access>
  @type elasticsearch
  host 127.0.0.1
  port 9200
  type_name apache_access
  logstash_format true
</match>

td-agentを再起動する。

以下のコマンドでtd-agentでapacheのログを監視しているか動作確認が可能。

# curl -XGET localhost:9200/_alias?pretty
{
{省略}
  "logstash-2021.05.30" : {
    "aliases" : { }
  }
}

f:id:mutaonet:20210530215117p:plain

次回はDBからデータを読み取り全文検索エンジンとしての運用を試みる。

ラズパイ4にElasticsearch+Kibanaインストール

暇だったのでラズパイ4にElaticsearchとKibanaをインストールしたときのメモ。

ちなみにすでにラズパイ4にはCentOS8が入っていてJava11もインストール済み。

Java8以降が必須になるみたいなので、ない場合は事前にインストールしておく。

すごくレベルの低い記事だと思う。

インストール

インストール方法を書こうかと思ったけど公式が正義なので割愛。

インストール手順を書いてもいずれ古くなるのでこういう場合は書かない方がいいと思う。

英語力0でも基礎中の基礎のLinuxの知識があれば問題なし。

Kibanaのインストール

www.elastic.co

Elasticsearchのインストール

www.elastic.co

firewall設定

# firewall-cmd --add-port=5601/tcp --permanent
#  firewall-cmd --reload

http://192.168.11.17:5601/ でブラウザにアクセスしてKibanaが表示されれば問題なし。

f:id:mutaonet:20210529172856p:plain

ハマったところ

Kibana server is not ready yet

公式の手順を踏まずに適当にインストールしてみたらKibanaの動作確認中にエラー発生。

ブラウザで表示したところ「Kibana server is not ready yet」とでる。

activeになっているのに何故?

# systemctl status kibana.service
● kibana.service - Kibana
   Loaded: loaded (/etc/systemd/system/kibana.service; enabled; vendor preset: disabled)
   Active: active (running) since Sat 2021-05-29 07:44:43 UTC; 4s ago
     Docs: https://www.elastic.co
 Main PID: 370443 (node)
    Tasks: 14 (limit: 23888)
   CGroup: /system.slice/kibana.service
           ├─370443 /usr/share/kibana/bin/../node/bin/node /usr/share/kibana/bin/../src/cli/dist --logging.dest=/var/log/kibana/kibana.log --pid.file=/run/kibana/kibana.pid
           └─370455 /usr/share/kibana/node/bin/node --preserve-symlinks-main --preserve-symlinks /usr/share/kibana/src/cli/dist --logging.dest=/var/log/kibana/kibana.log --pid.file=/run/kibana/kibana.pid

ログを確認してみると以下の記載があった。

{"type":"log","@timestamp":"2021-05-29T07:38:29+00:00","tags":["error","savedobjects-service"],"pid":370285,"message":"This version of Kibana (v7.13.0) is incompatible with the following Elasticsearch nodes in your cluster: v7.10.2 @ 127.0.0.1:9200 (127.0.0.1)"}

ElasticsearchとKibanaのバージョンが異なっているとのこと。 これは公式の手順通りreinstallすれば直った。

Kibana起動失敗

# systemctl start elasticsearch.service
Job for elasticsearch.service failed because the control process exited with error code.
See "systemctl status elasticsearch.service" and "journalctl -xe" for details.

journalctl -xe で確認詳細を確認しろとでているが、ログを見た方が早かった

cat /var/log/elasticsearch/elasticsearch.log
Caused by: java.nio.file.AccessDeniedException: /var/lib/elasticsearch/nodes/0/node.lock
    at sun.nio.fs.UnixException.translateToIOException(UnixException.java:90) ~[?:?]
    at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:106) ~[?:?]
    at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111) ~[?:?]
    at sun.nio.fs.UnixFileSystemProvider.newFileChannel(UnixFileSystemProvider.java:182) ~[?:?]
    at java.nio.channels.FileChannel.open(FileChannel.java:292) ~[?:?]
    at java.nio.channels.FileChannel.open(FileChannel.java:345) ~[?:?]
    at org.apache.lucene.store.NativeFSLockFactory.obtainFSLock(NativeFSLockFactory.java:125) ~[lucene-core-8.8.2.jar:8.8.2 a92a05e195b775b30ca410bc0a26e8e79e7b3bfb - mdrob - 2021-04-06 16:33:27]
    at org.apache.lucene.store.FSLockFactory.obtainLock(FSLockFactory.java:41) ~[lucene-core-8.8.2.jar:8.8.2 a92a05e195b775b30ca410bc0a26e8e79e7b3bfb - mdrob - 2021-04-06 16:33:27]
    at org.apache.lucene.store.BaseDirectory.obtainLock(BaseDirectory.java:45) ~[lucene-core-8.8.2.jar:8.8.2 a92a05e195b775b30ca410bc0a26e8e79e7b3bfb - mdrob - 2021-04-06 16:33:27]
    at org.elasticsearch.env.NodeEnvironment$NodeLock.<init>(NodeEnvironment.java:207) ~[elasticsearch-7.13.0.jar:7.13.0]
    at org.elasticsearch.env.NodeEnvironment.<init>(NodeEnvironment.java:262) ~[elasticsearch-7.13.0.jar:7.13.0]
    at org.elasticsearch.node.Node.<init>(Node.java:368) ~[elasticsearch-7.13.0.jar:7.13.0]
    at org.elasticsearch.node.Node.<init>(Node.java:278) ~[elasticsearch-7.13.0.jar:7.13.0]
    at org.elasticsearch.bootstrap.Bootstrap$5.<init>(Bootstrap.java:217) ~[elasticsearch-7.13.0.jar:7.13.0]
    at org.elasticsearch.bootstrap.Bootstrap.setup(Bootstrap.java:217) ~[elasticsearch-7.13.0.jar:7.13.0]
    at org.elasticsearch.bootstrap.Bootstrap.init(Bootstrap.java:397) ~[elasticsearch-7.13.0.jar:7.13.0]
    at org.elasticsearch.bootstrap.Elasticsearch.init(Elasticsearch.java:159) ~[elasticsearch-7.13.0.jar:7.13.0]

どうやらlockファイルにアクセスできていない模様だったので下記を実行。

chown -R elasticsearch:elasticsearch /var/lib/elasticsearch

これで素直に起動できました。

# systemctl status kibana.service
● kibana.service - Kibana
   Loaded: loaded (/etc/systemd/system/kibana.service; enabled; vendor preset: disabled)
   Active: active (running) since Sat 2021-05-29 08:06:23 UTC; 6s ago
     Docs: https://www.elastic.co
 Main PID: 371737 (node)
    Tasks: 14 (limit: 23888)
   CGroup: /system.slice/kibana.service
           ├─371737 /usr/share/kibana/bin/../node/bin/node /usr/share/kibana/bin/../src/cli/dist --logging.dest=/var/log/kibana/kibana.log --pid.file=/run/kibana/kibana.pid
           └─371749 /usr/share/kibana/node/bin/node --preserve-symlinks-main --preserve-symlinks /usr/share/kibana/src/cli/dist --logging.dest=/var/log/kibana/kibana.log --pid.file=/run/kibana/kibana.pid