たなしょのメモ

日々勉強していることをつらつらと

# 本気で学ぶ Linux実践入門 サーバ運用のための業務レベル管理術をよんだので感想 本気で学ぶ Linux実践入門 サーバ運用のための業務レベル管理術を少し前に読んだので感想を書きいていきます。
(かなりうろ覚えです)

この本はUbuntuDebian系)とCentOS(レッドバット系)の二つのOSの視点から各コマンドの動作を確認できるので、現場にあるほとんどのサーバーに対して知識をつけることができます。
自分は今回やらなかったのですが、DockerやVirtualBoxを使って仮想環境を構築して本に記載されているコマンドを実行してみると更に深く学べると思います。

個人的に良かったと思う点はsystemdとブートシーケンスについて書かれている点だと思います。
コマンドが網羅されているコマンド集にはsystemdも言及はないため勉強になりました。
実際にsystemctlコマンドを使用してhttpdなど各種デーモンを起動、実行していくチュートリアルもあります。

今後もLinux環境を構築するときに手元に置いてリファレンス的に読んでいくにはいい本だと思いました。
時間があるときにDockerで仮想環境を建てて色々なコマンドを試してみよう思います!

Rustで簡易なシェルを作成する

今回はRustの勉強ついでに簡単なシェルを作成してみようと思います。

今回作るシェルについて

今回作るシェルは下記の機能があるシェルを作成します。

  1. cd
  2. Unix準拠のコマンド
  3. コマンドのオプションへの対応
  4. パイプライン

Rustで作成してみる

処理は大まかに以下のようになりました。

  1. 標準入力を読み込む
  2. "|"で文字列を区切る
  3. 2.で区切った文字列をさらに"空白"で区切る
  4. 3.で区切った文字列を順番に取り出して各コマンドを実行する

大まかなソースコードは以下のリンク先にあります。 https://github.com/jacoloves/rust-shell/blob/master/src/main.rs

苦労した点

苦労した点は以下の2点でした。

  1. cdがシェルの中に組み込まれたコマンドだったので、別途作成が必要だった。
  2. パイプラインの実装

1.はPath::newディレクトリのパスを作成して、env::set_current_dirを使用して作業ディレクトリを変更するようにしました。
2.はpeekを使用して、コマンドに続きがあるかを確認して続きが存在する場合はStdio::pipedを使用して親プロセスから子プロセスへのパイプを作成するようにしました。
コマンドの続きがない場合は、Stdio::inheritを使用して親プロセスの処理をそのまま実行するようにしました。

今後について

今回はcdとパイプラインを実装した簡易なシェルを作成しましたが、今後は色々な機能を持ったもう少し大きなシェルを作成してみたいです。

最後に

Rustは色々なライブラリが揃っているので、低いレイヤーのアプリケーションを作成するのにも便利です。

ローカル環境でACLライブラリをincludeさせたい

ABCの問題を解く際にどうしてもACLライブラリをローカル環境でincludeしてみたかったので試してみました。

下記のgccのオプションで現在のincludeしているディレクトリを見ることができます。

$ gcc -x c++ -v -E /dev/null
(中略)
#include "..." search starts here:
#include <...> search starts here:
 /usr/include/c++/11
 /usr/include/x86_64-linux-gnu/c++/11
 /usr/include/c++/11/backward
 /usr/lib/gcc/x86_64-linux-gnu/11/include
 /usr/local/include
 /usr/include/x86_64-linux-gnu
 /usr/include
(中略)

この中だと/usr/local/includeの中にatcoderディレクトリを入れてあげればinlcludeできそうです。
(その他のディレクトリは色々なものが入っていて管理が大変そうなのでコピーしないほうが無難です。)

git clone https://github.com/atcoder/ac-library.git
cd ac-library
sudo cp -rp atcoder /usr/local/include/

atcoderディレクトリを/usr/local/include配下に置くことができたので、以降C++書く際に下記のようにincludeできます。

include <atcoder/all>

これでACLライブラリが使えるようになりました。

プログラミング言語Rust公式ガイドをよんだので感想

TRPL読みました

ようやくRustの学習を初めてTRPLの本を読み切ることができました。
インターネットでTRPLで無料で読めるのですが、
今まで何度も挫折してきたため本を買うことで読みきれるかなと思い、購入しました。
結果として読み切ることができたので本を買って大正解でした。

実際TRPLを読んでみて学べた知識も多くありました。
特にmatchアームとイテレータの説明がわかりやすく、TRPLを読んでいなかったら
今頃Rustを使って競技プログラミングをやっていないと思います。
Rustでバグが少ない理由の一つにmatchアームの存在があることも知ることができました。
(よく最後に「-」のパターンを使うのを忘れてコンパイルに怒られます汗)

またRustはイテレータも優秀でイテレータのトレイトを見ると本当に多様な使い方ができることにびっくりしました。
C++にもイテレータがあり競技プログラミングでお世話になっているのですが、
C++イテレータを更に拡張したような形で色々な機能がRustのイテレータにはあることがわかりました。

他に参考になったのはジェネリック型の使い方です。
Javaや最近のGoでも使われていますがRustでその使い方や強力な機能を知ることができました。
どんな型でも受け入れてくれるというのは関数を作成する上で大変強力な武器になり、
ソースコードを短く簡潔に書くことができるようになりました。

反面後半のスマートポインタ、並行性、ライフタイムは正直理解できませんでした。
翻訳されている本なので書き方も日本語が難しかったのも要因かもしれません。
最後にWebサーバーを自作するのですが半分も理解ができず写経していて挫折するところでした。
理解できない点はこのサイトがわかりやすそうだったので取り組んでみて理解していきたいと思います。

正直難易度は割と高い本だと思うのでRust初心者がいきなり読むのは難しいかもしれませんが、
入門書を一冊読み終えた人が読んでみると新しい発見があるかもしれません。

TRPLを読んでRustのことが少しだけ理解できてRustに対するモチベーションが上がりました!
今後もなにかツールを作成したり競技プログラミングをやる際は積極的にRustを書いていこうと思います。

2022年の振り返り

あけましておめでとうございます。
2022年も終わってしまいましたが一応振り返ってみようかと思います。
会社とプライベート両方を書いていこうと思います。(会社のことは少しだけ書こうと思います。)

開発

コードをたくさん書いた年になりました。
中でもVimScriptの出会いは大きくプラグインを作るのがとても楽しかったです。
特にvim-ChangeLogはGW中に作成して、
初めてGitHubでスターを得ることができたリポジトリでした。とても嬉しかったです。

またGoにもたくさん触れました。
小さいCLIツールを何個も作っては壊しを繰り返しました。
特に記憶に残ってるのはGoで祝日のAPIを作成したり、エスケープシーケンスを多用してFF6のモーグリをうごかしたりしました。
その他にも業務用のツールとしてagoutiを使ってスクレイピングツールGitのmasterブランチを素早く取り込むツール(開発中)を作りました。
Goは本当に書きやすい言語でCを書いていた私にはとても手に馴染む言語です。

後半になってくるとRustの記事を多く見かけるようになり、Rustの勉強をし始めることにしました。
Rustは学習コストが高いと言われていますがたしかに高いと思いました。
所有権やライフタイムという概念を理解してないので簡単なツールを作成するのもコンパイラに怒られながら作成していました。
Rustはコンパイラがとても優秀なので、開発者の理解が不完全でもコンパイラの指示に従えばある程度形になるものが作れるのは魅力的なのですが
自分が理解していない状態でコードを書いてるのは何が起きてるかわからない怖さみたいなものがあるので今年も引き続きRustの勉強を続けていこうと思います。
この頃Rustで作ったツールは主にLinuxのコマンドをCからRustに書き換えるのをメインになっていました。
treeの代わりとなるツールを作成したり、wcの代わりとなるツールを作成したりふつりな本ソースコードをRustに書き換えることをしてみたりしました。
どれも中途半端なプロジェクトになってしまっているので今年は作り切れるようにがんばります。

今はRustを趣味で書く機会が多いですが、今年もGoを書く機会があったら書いていこうと思います。(会社で使用するツールはGoで書いていく予定です。)

興味の範囲など

2022年の前半はソフトウェアエンジニアになりたいという漠然とした目標だけで日々業務をこなして、プライベートでも開発が楽しいのでなんとなくいろいろなものに手をつけては飽きてまた別の技術に手を出してを繰り返していました。
読んでいた本もCSSの本からLinuxの本、Go言語の本、CSの本など色々なものに目を通してきました。
今の会社にはPLになることを期待されているのですが、入社当初からのリーダーになりたいという思いはほとんど消えてしまっていました。
また自分がバックエンドエンジニアとして伸び悩んでいることに気づき始めてました。
会社のバックエンドの開発もなんとなく言われたことはできるのですが、それよりもプラスになることはできず案件以外でもこれ以上技術的に貢献できないと感じました。
会社の方針上、几帳面な人のほうが評価される傾向にあることを知り大雑把な性格の私は評価されるのは難しいとも感じました。
「バックエンド向いてないのかな」と悶々とした思いで前半は過ごしていました。

そんな中ある日ふっと今まで色々なことを勉強してきて、その中でも低レイヤやインフラなどの比較的下のレイヤーを勉強している割合が多いことにきづきました。
開発の章でも触れましたが、VimやGo、Rustを触っていることが多かったので自然とターミナルの中で開発してるのもあり「将来はCLIを使ったインフラを支えるエンジニアになりたい」と思うようになりました。
ですがインフラの実務経験がない私のようなエンジニアを雇ってくれるところは皆無だと考え資格を取ることにしました。
インフラ系の資格で思いついたのはLPICCCNAの2つを思いつき、LPICは今後もLinuxの本や趣味でLinuxを触ってる中で知識を身につければいいと考え一旦後回しにしてCCNAの資格を取ることにしました。
ネットワークエンジニアにも興味があったので日経ネットワークを読んだり、ネットワークに関する本を読んだりしてたのでCCNAの触りの部分はある程度理解できたのですがルーターやスイッチ、セキュリティなど大部分はまるっきり理解できていなかったので勉強しました。 CCNAの勉強を通して今まで当たり前に使われているネットワークがどのようにつながっているかなど裏側を知ることができますます勉強が楽しくなりました。
勉強のおかげもあってCCNAというネットワークエンジニアの登竜門的な資格を取得できたのは本当に良かったです。
今後もネットワークやLinux、低レイヤーの知識を身につけインフラに携われるエンジニアになれるように精進していきたいと思います。

会社のことなど(少しだけ)

「興味の範囲など」で書いたように悶々とした日々を送っていましたが、それ以外はとても落ち着いた一年でした。
残業もほとんどなく定時後にやりたいことができる環境は最高でした。
私の主な役割としては未経験のエンジニアのOJTでした。OJTは過去にも色々とやってきたのですが今回のOJTが過去一人に対して優しく接せられたのかなと個人的には思います。
残業もなく人には恵まれ、会社も変化していこうという姿勢を感じるいい会社ではあるのですが、いかんせんレガシーなシステムを保守し続けなくてはいけないので飽きているというのも本音です。
組織側からもPLになるために早く業務知識をつけてほしいと言われているのですがあまり覚える気もなく、PLになりたいという意欲もないので無理のない範囲で技術を身につけて自分の力で貢献できるところは貢献していくのが目標になります。

最後に

ここまで駄文を書き散らしましたが、無理なく色々な知識を身につけられて、将来のキャリアもなんとなくですが見えてきた1年になりました。
今年は無理なく組織に貢献できるところは貢献していくゆるい感じで頑張っていこうと思います。
良い一年でありますように〜!

達人に学ぶDB設計を読んだので所感

達人に学ぶDB設計を読んだので所感を書いていきたいと思います。
日ごろ何気なく使っているDBについて深く学ぶことができたのでとてもいい本でした。
会社の同僚にも勧めてみたいと思います。

1章

データとは何か、なぜデータベースが必要なのか、本書で学んでいくことについて書かれていました。
概念スキーマの話は分かりやすくて理解できてない部分の補完になりました。
「最初にデータがあり、次にプログラムがある」という考えたは普段何気なくツールを作ってしまう自分には刺さる言葉でした。ちゃんとデータから考えないとなーと改めて思いました。
またDBMSのマニュアルを熟読することがDBの勉強になるらしいので機会があれば読んでみたいと思います。

2章

物理設計周りの説明がされていました。
RAIDの説明と各種バックアップの説明にページが割かれていてその二つのトピックの学習によかったです。
RIADやバックアップの選択は全てトレードオフの関係にあること、本書を読んでいくと「トレードオフ」とい言葉が多く散見されますが、それくらいDBの物理層というのものはシビアな関係なのだと思いました。

3章

テーブル定義や正規系の話がメインでした。
特に正規化の方法を説明してる箇所はとても分かりやすく記載されていたので、今後も読みかえすと思います。
テーブル名は複数形や複数名詞で書くことや外部キーは親子関係なのでこのデータから先に削除することなど知らなかったことが多く学べる章でした。

4章

ER図の記法について書かれていました。
資格の勉強の際に一通り覚えていたので復習になりました。

5章

正規化と非正規化のメリットデメリットについて書かれていました。
「正規化は可能な限り高次にすることが大原則」ですが、正規化をするとテーブルを分割するのでJOIN句が増えてしまい検索パフォーマンスは落ちる。
それでも非正規化が最後の手段として取っておき、別の方法でパフォーマンスを向上させた方がよいとのことでした。
余談になりますがSQLを考えるときのコツとして「FROM→WHERE→GROUP BYの順で考えたほうが簡単」と記載があり確かになーと膝を打ちました。

6章

統計情報とインデックスについて書かれていました。
B-treeインデックスが一番ポピュラーであることやデータ量が少ない場合はインデックスが意味がないこと、インデックスを貼った値は単体で検索させるなど、今までインデックスについて曖昧にしか理解してなかったのでとても勉強になりました。
統計情報についても全く知らなかったので各データに行きつくまでの地図だという解釈ができただけでも良かったです。

7章

テーブル設計のバッドノウハウについて学びました。
悪いテーブル設計というのは「何も考えてない」から生まれることと記載がありその通りだと思いました。
バッドノウハウというのは列の意味を決めたら変更しないことや単一参照テーブルを作成しないことなどがあげられるみたいでした。
1~6章で学んだこともそうなのですが、何よりも「よく考えて」テーブルを設計するのが大事だと思いました。

8章

グレーケースについて記載がありました。
グレーケースの例が何点かあったのですが、一番衝撃を受けたのはオートインクリメントは主キーとしては使わない方がよく、あくまで代理キーとして運用するべきだという考え方でした。
自分でなにかアプリを作成する際は主キーをオートインクリメントではなく固定長のデータにしようと思いました。
また、ビューはSELECT文の書かれたファイルなので、ビューにSELECT文を投げるということは2回SELEC文を投げていることになることも初めて知りました。

9章

木構造のデータをリレーショナルデータベースに格納する方法について記載がありました。
今までは隣接リストモデルしか知らなかったのですが、入れ子集合モデルや入れ子区間モデルなどのモデルが存在することを知りました。
中でも入れ子区間モデルが更新処理のパフォーマンスがよいそうです。
木構造のデータを見たことがないので全体的にイメージがわきにくかったです。

まとめ

今まで何も考えてなく既存の踏襲という方法でテーブルを設計していたことを痛感しました。
特に正規化やバッドノウハウについて知れたので次回テーブル設計をするときやテーブルをレビューするときは参考にしたいです。
最後にDBとは関係ないのですが「上級レベルのことを学ぶには英語が必要だと」という文言はまさに通りだと思いました。今後も英語の研鑽も頑張っていきたいです。

「Linuxで動かしながら学ぶTCP/IPネットワーク入門」を読んだので所感

Linuxで動かしながら学ぶTCP/IPネットワーク入門を読みました。
現在CCNAの資格を取得するために勉強中なのですがその副読本としてとても良い本でした。
今まで本や資格の勉強の中でしか見てこなかったネットワークの動きがわかりました。

2章

この章ではTCP/IPの概要が説明されていました。
TCP/IPの代表的なプロトコルOSI参照モデルpingtcpdumpについて学びました。
特にtcpdumpは今まで存在は知っていましたがあまり使ってこなかったためとても参考になりました。
主にこの本ではtcpdumpを起動したまま後述するルーターやGWに送ったパケットの流れを追うのに使いました。

3章

実際にNetwork Namespaceを使用して、
仮想のネットワークを作成してお互いに通信させて動作を確かめました。
以下はその際に使用したコマンドです。

① Network Namespace(今回はns1という名称にします)を作成します。

sudo ip netns add ns1

Network Namespace同士をつなぐため、vethインターフェースを作成してNetwork Namespaceに割り当てます。
② vethインターフェースを作成します。

sudo ip link add ns1-veth0 type veth peer name ns2-veth0

③ vethインターフェースをNetwork Namespaceに割り当てます。

sudo ip link set ns1-veth0 netns ns1

④ IPを使って通信するためIPアドレスとをvethインターフェースに割り当てます。

sudo ip netns exec ns1 ip address add 192.0.1.2/24 dev ns1-veth0

⑤ ネットワークインターフェースを立ち上げます。

sudo ip netns exec ns1 ip link set ns1-veth0 up

以上の設定が正しく行う(対向のNetwork Namespaceも必要なのでもう一度同じコマンドを入力します)と
pingで疎通確認できます。

ルーターを交えてセグメントをまたいで通信する過程も学びました。 その際はNetwork Namespaceに新しく「router」を追加して、gw-veth0,1というvethを用意しました。

4章

イーサネットについて学びました。
実際にNetworkNamespaceにMACアドレスを設定することで、ルーターを経由するとパケットが積みかえるい動きが読み取ることができました。

MACアドレスを指定するコマンドです。

sudo ip netns exec ns1 ip link set dev ns1-veth0 address 00:00:5E:00:53:01

tcpdumparpのやり取りを確認するコマンドです。

sudo ip netns exec ns1 tcpdump -tnel -i ns1-vetho0 icmp or arp

5章

トランスポート層プロトコルTCP/UDP)について学びました。
netcatコマンドtcpdumpコマンドを使ってパケットの動きを観察しました。

① netcatでudpを見るコマンドです。 オプションの-uがUDPで通信することを指定しています。

nc -u 127.0.0.1 1234567

② netcatでtcpを見るコマンドです。 何もオプションを指定しなければTCP通信になります。

nc 127.0.0.1 1234567

6章

アプリケーション層のプロトコル(HTTP、DNSDHCP)について学びました。
dnsmasqコマンドを使用してDHCPサーバー作成しました。

sudo ip netns exec server dnsmasq \
--dhcp-range=192.0.2.100,192.0.2.200,255.255.255.0
--interface=s-veth0
--port 0
--no-resolv
--no-daemo

7章

NATについて学びました。
NATにはSourceNAT、DestinationNATの二つが主にあります。
SourceNATは一般的に本で書かれているNAT、NAPTのイメージで送信先がグローバルアドレスで、送信元がプライベートアドレスになっているパケットのヘッダです。
DestinatioNATはSourceNATの逆で送信先がグローバルアドレスになっているパケットをプライベートアドレスに書き換えます。
「ポートを開ける」という言葉は実はグローバルアドレスをプライベートアドレスに変換するDestinationNATが動作しているポートを指定したことがわかりました。

8章

ソケットプログラミングの実践ということでPythonでHTTPクライアント、エコーサーバ、バイナリベースのプロトコルを作成しました。
Pythonで書いたコードをGoやRustで書き換えるのも面白そうなので今度挑戦してみようと思います。

まとめ

CCNAの副読本として最適だと思いました。
今まで文章でしか見たことなく実際に動いてる場面を見る事がなかったイーサネットなどの動きが学べたのはとてもよかったです。
この本を足がかりに他のネットワークの本にもチャレンジしたいです。