ヒトリ歩き

愚痴とかいろいろ書きます

2025年6月の振り返り

ブログをサボって早1年経過しようとしていた。

 

お仕事

ブログをサボりだしたときにプロジェクトが変わって、夜が遅くなって朝活が厳しくなり...

 

まー。言い訳です。

 

途中で、育成兼ねてプロジェクトリーダーになりました。リーダー業務を全て巻き取ってないけど、色々言われてすでに気が滅入っている。

リーダーになる前からちょこちょこ言ってたが、周りに響かず、負債を抱えた状態でリーダーになってしまった。

全部を巻き取らないといけないが、果たして私にリーダーが出来るのか....

日々、不安でしかない。

 

リーダーになってみて思うこと

 

リストと課題をいかに抽出して管理していくかというのは改めて重要と感じた。

そして、プロジェクトメンバーから全く課題やリストが出てこないのは正常なプロジェクトではないと考える。

メンバーが作業をやり始めて、これが足りないとかその状況にならないと出てこないのは一人一人がゴールに目を向けてないからじゃないかなと思う。

そう考えると、プロジェクトリーダーになる前は、めちゃくちゃ課題あげたり、リスクあげたりしてたな...

スケジュールに余裕があったのもあるが、全然休出とかなく過ごせていたので、課題やリスク管理は大事だ。

 

優しさ < 厳しさ

周りのリーダーは優しいみたいだけど、自分は優しくできない。

なんで、作業遅れの責任を自分が持たないといけないのか?

成果物の責任はリーダーが持つ必要があるが、成果物の責任は作業者にあるわけだから、責任はきちんと持ってもらいたい。

だから、私は優しいプロジェクトリーダーにはなれない。

 

最後に

ブログは月1回は投稿しようと思う。

最近、リーダーの本を読んでこれはよかった。

 

 

次はこれらを読みたい。

 

 

 



 

2024年9月の振り返り

プロジェクトの方は何とも言えない感じ。
声に出して楽しいと言えるようなプロジェクトではないが、自分が知らなかったこと、新しいことに出会えているので その瞬間は不安や焦りが出てしまうが、なんとか学びながら進みたい。 とりあえず、今のところは順調なはず。

朝活または夜活を20分やる

9月もやり切った。 BINDをやってみたり、Pythonのroadmapを使って、基礎を見直してみた。 新しい気づきもあったが、記事に出来なかったのは残念。 今は、AWS ASSの取得のために時間を使っている。

roadmap.sh

ブログはお休み

9月は、3187PVだった。
朝活または夜活の時間をAWS ASSの資格取得に向けて時間を使うことにした。
これもあれもとなると、どっちつかずになってしまうので、資格を取ることを優先するためにブログは一旦お休みする。

資格の勉強

ちょっとしたきっかけがあったので、朝活または夜活とブログを書く時間を利用して、勉強中。
資格勉強自体が苦手なので、受かることができるかどうか不安でいっぱい。
人よりも時間がかかってしまうし、暗記力もないので、不安だらけ。 とりあえず、10月末には合格していたい。

最近、思うこと

HIITをやり始めたが、出社した日は遅く帰ってきて、すぐに夕飯を食べないと怒られるので、 食後にHIITをするとめっちゃきついのね。
だから、出来て週一しか出来てなかった。
テレワークの日は朝に走ったら、そこでHIITを始めたおかげか思いのほか走れて、ちょっと嬉しかった。
そして、資格取得に向けて勉強時間を確保するために、朝5時から5時半の間に起床して勉強してたんだが、一昨日発熱。
睡眠時間が確実に減っていたのは、わかってたけど、こんなに早く体調を崩すとは、つくづく自分の身体の弱さがなさけなくなる。どうやったら、風邪をひかずに一年過ごせずのか知りたい。
というわけで、病み上がりなので、HIITとかランニングは1週間ほどサボり期間で、また来週から頑張ろう。

ExceptionGroupでExceptionをまとめる

改めて、Pythonの基本の見直そうとroadmapをベースに記事を読んだり、マニュアルを読んだりしている。 その時に、ExceptionGroupの存在を知った。

ExceptionGroupは、バージョン3.11で追加されている。

何をするためのものか?

マニュアルと見ると以下のように書かれている。

最初の例外を送出するよりも、処理を継続して複数の例外を集約した方が望ましいユースケースもある。 組み込みのExceptionGroupは例外インスタンスのリストをまとめ、同時に送出できるようにする。 ExceptionGroupも例外なので、他の例外と同じように捕捉できる。

複数の宛先に非同期で通信した際に、例外が発生してもそのまま処理して、最後に呼び出し元に例外を送出するような場合が1つあると思う。

どうやって使うのか?

ExceptionGroupは、例外を配列でまとめたものを渡してインスタンスを生成する。 以下の場合は、OSErrorとSystemErrorを配列に入れている。

    excs = [OSError("error 1"), SystemError("error 2")]
    raise ExceptionGroup("there were problems", excs)

例外を捕捉する側は、通常はexceptを使用するが、ExceptionGroupに含まれる例外に対して処理をしたい場合は、 except*を使用する。 以下の場合、ExceptionGroupに含まれるOSErrorとSystemErrorがそれぞれの節で処理される。

def f():
    excs = [OSError("error 1"), SystemError("error 2")]
    raise ExceptionGroup("there were problems", excs)

try:
    try:
        f()
    except* OSError as e:
        print("There were OSErrors")
    except* SystemError as e:
        print("There were SystemErrors")
except Exception as e:
    print(f"raiseされたよ {type(e)}")

except*節で例外を送出したらどうなる?

expcet*内で例外を送出すると上位側にはOSErrorとSystemErrorが含まれたExceptionGroupが送出される。そのため、個々の例外がそう送出されることはない。

def f():
    excs = [OSError("error 1"), SystemError("error 2")]
    raise ExceptionGroup("there were problems", excs)

try:
    try:
        f()
    except* OSError as e:
        print("There were OSErrors")
        raise Exception("OSErrosだよ")
    except* SystemError as e:
        print("There were SystemErrors")
        raise Exception("SystemErrorsだよ")
except Exception as e:
    print(f"raiseされたよ {type(e)}")

最後に

ExceptionGroupというものがあることを全く知らなかったのでよい勉強になった。引き続き、roadmapを参考に基礎部分を復習してPythonの理解を深めようと思う。

参考

docs.python.org

roadmap.sh

SQLAlchemyでのJoinで結合したデータを取得

前回、SELECT 〜 JOIN をやってみたが、期待通りのことが出来なかった。 少し調べたら、やり方がわかったのでまとめておく。

kotapontan.hatenablog.com

selectメソッドに対象のモデルを指定する

selectメソッドで検索時に取得するデータのモデルを指定して、executeメソッドを実行するだけ。 scalarsメソッドは特定のカラムの値を抽出するために使用するため、scalarsメソッドでデータ取得するとStudentテーブルのデータが取得できない。 executeメソッドは、全体の結果を取得するため、結合して取得したデータに対して、対応するモデルに値を設定してくれる。

stmt = select(School, Student).join(School, Student.school_id == School.id)

results = session.execute(stmt)

値の参照方法

以下のように、Rowインスタンスモデルクラス.変数名でアクセスできる。 Studentテーブルのnameカラムの値を取得したい場合、Rowインスタンスの変数名.Student.nameで取得する。

    print("student.id = " + str(result.Student.id))
    print("student.name = " + str(result.Student.name))
    print("student.school.name = " + str(result.School.name))

最後に

SQLAlchemyのマニュアルに複数のORMエンティティを使用する場合について記載されていた。やりたいことがマニュアルに書かれていたので、改めてマニュアルを確認することは大事だと気付かされた。

参考

docs.sqlalchemy.org

docs.sqlalchemy.org

docs.sqlalchemy.org

ソース

from sqlalchemy import create_engine
from sqlalchemy.types import Integer, String
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import relationship
from sqlalchemy import ForeignKey
from sqlalchemy import select


class Base(DeclarativeBase):
    pass


class Student(Base):
    __tablename__ = "student"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(30))
    school_id: Mapped[int] = mapped_column(ForeignKey("school.id"))


class School(Base):
    __tablename__ = "school"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(30))


# DBエンジンを作成
url = "postgresql://postgres:example@localhost:5432/postgres"
engine = create_engine(url, echo=True)

# テーブルをDBに作成
Base.metadata.create_all(engine)

# セッションを作成
# セッションを介してクエリを実行する
SessionClass = sessionmaker(engine)
session = SessionClass()

school1 = School(name="あいうえお学園")
school2 = School(name="かきくけこ学園")
school3 = School(name="さしすせそ学校")
session.add_all([school1, school2, school3])
session.commit()
student1 = Student(name="sato", school_id=1)
student2 = Student(name="tanaka", school_id=2)
student3 = Student(name="watanabe", school_id=3)
session.add_all([student1, student2, student3])
session.commit()

stmt = select(School, Student).join(School, Student.school_id == School.id)


# results = session.scalars(stmt)
results = session.execute(stmt)

for result in results:
    print("student.id = " + str(result.Student.id))
    print("student.name = " + str(result.Student.name))
    print("student.school.name = " + str(result.School.name))
version: "3.1"

services:
  db:
    image: postgres
    restart: always
    environment:
      POSTGRES_PASSWORD: example
    ports:
      - 5432:5432

  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080

2024年8月の振り返り

8月から徐々に新しいプロジェクトの作業が始まった。 夏季休暇前は気持ちがのってなかったが、休み明けは気持ちを切り替えて作業が出来ているように 思える。 だが、リーダーの立ち位置ではないので、今後リーダーとなりマネージャになれるのか不安もある。 今は、今できることを全力でやろう。 新しいプロジェクトでは、「楽しむ」ということを目標にする。 きっと、進捗が遅れて、上位上司に怒鳴られる場面が出てくるはず。(現実になるかはわからん) そんな時でも、マイナスにならず、周りに声をかけて「楽しむ」というのを意識したい。 この「楽しむ」ということが出来れば、リーダーとしてもやっていけるんじゃないかなと。 自分のマインドは常にマイナスなので、マインドを変えるチャンスにもなるはずだ。

朝活または夜活を20分やる

夏季休暇もあったが、帰省先にもMacBookを持ち帰って実施出来た。 2021年に5か月しか継続して出来なかったことが8か月続けられている。 残り4か月を何とかやり切りたい。 きっと、1年通してやれれば、自信にも繋がるはずだ。

先月のPV数を更新

8月も週1ペースを維持できた。 1日のPV数も初めて200PVを超えることができた。また、8月は、3461PVだった。 9月も週1ペースは維持していきたい。

資格の勉強

腹を括れていない。どうしましょうという感じ。

最近、思うこと

最近、思うことと言うか、夏季休暇明けたら体重が3キロぐらい増加していた。 Tシャツを着て、鏡を見るとお腹が出ているように見える。さすがにやばいなと思ったのと習慣化するアプリを 試していることもあり、HIITを始めた。 学生時代は、めちゃくちゃ動き回っていたが、就職してデスクワークになり、学生時代の反動でかきつい運動はしたくなくなった。 その結果、HIITやり始めたら、めちゃくちゃきつい。 高強度トレーニングなので、きついのは当たり前なのだが。始めたけど、全く痩せずで... 習慣化と合わせて、継続できるようにしたい。 問題は、出社したときにいつやるか。朝するのか?帰宅してするのか?

DRBDによるリアルタイムミラーリング

モチベーション

HA環境を構築する際に、プロジェクトでrsyncを使ってファイルの同期をしていた。 ただ、pacemakerで検索するとDRBDを組み合わせて使う記事がいくつか見られたので、DRBDを試してみて、どういったものなのかの概要を掴む。

DRBDとは

DRBD(Distributed Replicated Block Device)とは、TCP/IPネットワークを通じて複数のサーバのストレージ(パーティション)をリアルタイムにミラーリング(複製)するソフトウェア。 RAID1のようなミラーディスクを構築が可能。 RAIDは、同じサーバ内のストレージを冗長化するが、DRBDは複数のサーバーのストレージを使用する。

https://bcblog.sios.jp/brbd-index/

DRBDとPacemakerを組み合わせると簡単かつ安全はハイアベイラビリティクラスタ環境(HAクラスタ環境)が構築可能。

環境

VagrantRocky linux 9VMを起動。 それぞれのVMにディスク(/dev/sdb)を追加しておく

前準備

Vagrantで構築するVMには、ディスクが1枚(/dev/sda)しかないので、/dev/sdbを追加しておく。 /dev/sdbを追加して、VMを起動したら、パーティションを作成しておく。 また、DRBDの定義でホスト名を使用するため、/etc/hostsにも定義を追加しておく。 検証環境のfirewallは停止したままとする。firewallを起動しておく場合は、7788-7799のポート番号の ポートの解放が必要になる。

firewall-cmd --permanent --add-port=7788-7799/tcp
firewall-cmd --reload

パーティションテーブルの作成

parted -s -a optimal /dev/sdb mklabel gpt

パーティションの作成

parted -s -a optimal /dev/sdb -- mkpart primary xfs 1 -1

hostsファイルの編集

vi /etc/hostsで下記の定義を追加する。

192.168.56.10 server1
192.168.56.11 server2

インストール

drbdとkmod-drbdをインストール(server1/server2の両方で実行)

rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
dnf install -y https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm
dnf install -y drbd9x-utils kmod-drbd9x

ファイルの同期のための定義ファイルを作成する(server1/server2の両方で実行)

vi /etc/drbd.d/drbd0.res

resource drbd0 {
        protocol C;

        disk /dev/sdb1;
        device /dev/drbd0;
        meta-disk internal;
        on server1 {
                address 192.168.56.10:7789;
        }
        on server2 {
                address 192.168.56.11:7789;
        }
}

メタデータの作成(server1/server2の両方で実行)

drbdadm create-md drbd0

下記のメッセージが出力される。

initializing activity log
initializing bitmap (320 KB) to all zero
Writing meta data...
New drbd meta data block successfully created.

リソースの有効化(server1/server2の両方で実行)

drbdadm up drbd0

実行すると以下のようなメッセージが出力される。

  --==  Thank you for participating in the global usage survey  ==--
The server's response is:

you are the 2106th user to install this version

状態の確認(server1/server2の両方で実行)

drbdadm statusを実行する。

drbd0 role:Secondary
  disk:Inconsistent
  server2 role:Secondary
    peer-disk:Inconsistent

diskがInconsistentになっているので、不一致の状態。

データ同期

server1をprimaryにするので、server1で実行する。

drbdadm primary --force drbd0

状態の確認

状態を確認するために、drbdadm status <リソース>を実行する。

drbdadm status drbd0

出力結果は以下のような出力になる。

drbd0 role:Primary
  disk:UpToDate
  server2 role:Secondary
    replication:SyncSource peer-disk:Inconsistent done:0.72

出力内容を確認すると以下のようになる。

出力 内容
drbd0 role:Primary コマンドを実行したサーバのroleを出力。server1はPrimary
disk:UpToDate DRBDで管理しているストレージの状態を表す
server2 role:Secondary 同期先のサーバのroleを出力。
replication:SyncSource peer-disk:Inconsistent done:0.72 同期状態を表す。同期中なのでdoneの値がコマンドを実行するたびに増加する

linbit.com

linbit.com

tech-lab.sios.jp

同期が完了すると以下のように、UpToDateの状態になる。

drbd0 role:Primary
  disk:UpToDate
  server2 role:Secondary
    peer-disk:UpToDate

動作確認

server1がprimaryなので、server1で作業を実施する。

mkfs.xfs /dev/drbd0
# 出力結果
meta-data=/dev/drbd0             isize=512    agcount=4, agsize=655274 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1, rmapbt=0
         =                       reflink=1    bigtime=1 inobtcount=1 nrext64=0
data     =                       bsize=4096   blocks=2621095, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=4096   blocks=16384, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

/dev/drbd0ファイルシステムを作成して、マウントする。 その後に、ファイルを作成して、アンマウントする。

mount /dev/drbd0 /mnt
echo "test" > /mnt/backup.txt
cat /mnt/backup.txt
test
umount /mnt

server2で/dev/drbd0にマウントし、ステータスを確認する。

mount /dev/drbd0 /mnt
drbdadm status drbd0

mountすると自動的にPrimaryに昇格され、 umountすると自動的にSecondaryに降格される。これは、DRBD9では自動プロモーションが有効になっているため。 server1でステータスを確認すると、Secondaryになっていた。

drbd0 role:Primary
  disk:UpToDate
  server1 role:Secondary
    peer-disk:UpToDate

server1で作成したファイルの内容を出力する。

cat /mnt/backup.txt

以下のメッセージが出力され、ファイルが同期されていることがわかる。

test

再起動したらステータスが見えない

サーバーを再起動すると、ステータスが見えなくなった。 原因は、DRBDのサービスが停止していたため。 DRBDをインストールした際に、サービスの自動起動設定はされないので、手動で設定する必要がある。

server1/server2でサービスを自動起動するように設定し、再起動。

systemctl enable drbd
systemctl reboot

サーバー再起動後に、drbdadm status allを実行して結果が取得できた。

drbd0 role:Secondary
  disk:UpToDate
  server2 role:Secondary
    peer-disk:UpToDate

www.bigbang.mydns.jp

最後に

ファイルはrsyncを使って同期をするものかと思っていたが、ブロックデバイスを同期するDRBDの存在を知ることが出来てよかった。 pacemaker+DRBDというは検索すると情報がそこそこあるが、プロジェクトで使っているところは聞いたことがないので、今後プロジェクトで使えるか検討してみたい。 mountすると自動でPrimaryに昇格するが、どのような設定をしたらPrimaryだけmountするのかがわからないので、pacemaker+DRBDをやる際に確認する。

参考

qiita.com

infra.blog.shinobi.jp

www.bigbang.mydns.jp

Vagrantで追加ディスクを追加する方法

VMにディスクが複数必要になったので、設定方法を調べて試した。 以下のdiskの定義を追加すればよい。 自分の環境だと、追加のディスクは/dev/sdbに追加された。

config.vm.disk :disk, size: "10GB", name: "extra_storage"

fdisk -lを実行して、/dev/sdbが追加されたことを確認できる。

# fdisk -l
Disk /dev/sdb: 10 GiB, 10737418240 bytes, 20971520 sectors
Disk model: VBOX HARDDISK   
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes


Disk /dev/sda: 10 GiB, 10737418240 bytes, 20971520 sectors
Disk model: VBOX HARDDISK   
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 31708F37-29EF-4E85-BE83-713DF6452BB1

Device       Start      End  Sectors  Size Type
/dev/sda1     2048   206847   204800  100M EFI System
/dev/sda2   206848  2254847  2048000 1000M Linux filesystem
/dev/sda3  2254848  2263039     8192    4M PowerPC PReP boot
/dev/sda4  2263040  2265087     2048    1M BIOS boot
/dev/sda5  2265088 18649087 16384000  7.8G Linux filesystem

参考

qiita.com