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 でテスト用のデータを事前に入れておく
実際にSELECT文を打ってみる
- 使用するモジュールをgo getで取得
go get github.com/go-sql-driver/mysql
- テスト用コード
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発見
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: プロセスが物理メモリを消費しているかを%で表示
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を書いた。
記載内容は何をするか簡潔にまとめたもの。
簡潔すぎてフリーダム。
今回の場合は四則演算ができる電卓のようなものを作ること。
失敗
成功
- 基礎的な文法をおさらいするにはよかったと思う。
今後について
サーバ/インフラを支える技術
1章 サーバ/インフラ構築入門
本書を読み終えたので軽くメモ。
クラウドが便利になって気にしていなかったところの知識やざっくりとした知識で捉えていたものが理解できるようになる良書だった。
ヘルスチェック
ICMP監視(L3)
echoを投げてリプライが来るか監視する。Webサービスのダウンは検知できない。
ポート監視(L4)
サービス監視(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インストール
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" : { } } }
次回はDBからデータを読み取り全文検索エンジンとしての運用を試みる。
ラズパイ4にElasticsearch+Kibanaインストール
暇だったのでラズパイ4にElaticsearchとKibanaをインストールしたときのメモ。
ちなみにすでにラズパイ4にはCentOS8が入っていてJava11もインストール済み。
Java8以降が必須になるみたいなので、ない場合は事前にインストールしておく。
すごくレベルの低い記事だと思う。
インストール
インストール方法を書こうかと思ったけど公式が正義なので割愛。
インストール手順を書いてもいずれ古くなるのでこういう場合は書かない方がいいと思う。
英語力0でも基礎中の基礎のLinuxの知識があれば問題なし。
Kibanaのインストール
Elasticsearchのインストール
firewall設定
# firewall-cmd --add-port=5601/tcp --permanent # firewall-cmd --reload
http://192.168.11.17:5601/ でブラウザにアクセスしてKibanaが表示されれば問題なし。
ハマったところ
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