自宅が麻雀スタジオになりつつある話

はじめに

この記事は whywaita Advent Calendar 2021 - Adventar 9日目の記事です。

adventar.org

8日目の記事は id:alstamber016 さんの ステイケーションをたのしもう - alstamber lab でした。

ワーケーションは興味があってリモートワークが続いているうちにやってみたいと思っていたのですが、ステイケーションという単語は始めて聞きました。ホテルというと旅行の際の宿と捉えがちですが、そもそもホテルに旅行しに行くという考え方は面白いですね!

whywaita との関係

私は whywaita advent calendar には初参加なのですが whywaita との関係は意外と古く、大学時代のサークルの交流会から始まり、某インフラコンテスト運営やしまいには同じ会社に入社して現在は whywaita 先輩の後輩として働いています。

というわけで今回は whywaita も参加している我が家で開かれている麻雀リーグ戦 (通称Gリーグ)

を、撮影して記録していますというお話をしていきたいと思います。

本編

まずは大まかな機材の配置図です。

f:id:gurapomu:20211208120244p:plain

一般的な独身男性の家ですのでもちろんテレビやデスクやテーブルやソファもおいてあるのがわかると思います。*1*2

撮影機材

撮影機材はこのようにして設置してあります。

f:id:gurapomu:20211208125043p:plain

ライトレールに、ドンキで売っていたスマホ用の三脚をくくりつけています。雲台のネジがプラスチックせいで、取り付けの際に1度折れました。*3

ハンディカムのバリアングルって便利ですよね、卓の位置調整が上を見るだけで行うことができます。まさかこのような使い方ができるとは。

f:id:gurapomu:20211208125204j:plain

ハンディカムの固定用に買ったスマホ用の三脚に付属していたクイックシュー(?)と、これまたドンキで売っていたちゃっちい三脚を利用して手牌カメラにしています。

編集環境

各機材はおおまかにこのように接続されています。

f:id:gurapomu:20211208131017p:plain

LiveShell PRO というのは Cerevo 社が出しているライブ配信用機材です。HDMI やピン端子の映像入力を RTMP や RTSP 形式で配信することができます。今回は、 RTSP 形式で編集ソフトに向けて配信を行っています。本来 LiveShell PRO には WiFi ドングルが付属しているのですが、長時間稼働させておくとドングルが熱を持ち頻繁に接続が切れるようになってしまいます。これを回避するために WiFi を一度 RaspberryPi 4 でブリッジし LiveShell 自体には有線で接続するという方式をとっています。

手牌用のカメラはすべて Android スマートフォンを利用しています。 RTSP Camera Server - Google Play のアプリ のようなアプリを利用することで RTSP で編集ソフトに向けて配信します。

f:id:gurapomu:20211208132139p:plain

これらで配信された RTSP ストリームを OBS からメディアソースとして受け取り、図左のように各動画を配置することで全5視点を同時に視聴することができるようになりました!!

f:id:gurapomu:20211208135405p:plain

課題点

  1. 手牌カメラの位置が近いせいで飲み物だとかをおいておく台を置くスペースがありません。部屋の広さの関係でこれ以上カメラを引けない席があります。
  2. ライトレールには当然ライトも付いているので照り返しがキツイです。場合によって写真左の人の河が見づらくなります。
  3. 天井カメラと手牌カメラの遅延の差が気になります。各機材のバッファサイズの調整でなんとかごまかしてます。

機材の紹介

それでは撮影に使用している機材を紹介していきます

www.amazon.co.jp

こちらが我が家で使用している麻雀卓です。まずはこれがないと麻雀ができません。6人で割り勘で購入したので一人頭の負担額は3~5万程度でした、安いですね。

www.amazon.co.jp

ハンディカムです。詳しい型番を覚えていませんがそんなに高くはなかったはず。

Amazon.co.jp : 共同照明 配線ダクトレール ライティング ダクトレール (GT-DJ-GDB)ライティングバー 1m シーリング用スポットライト おしゃれ レール 天井照明簡易取付 レールライト用 レール照明 黒 : ホーム&キッチン

ライトレールです。カメラの固定だけでなく、RPi や LiveShell の電源確保にも重宝しています。

Amazon | 「2021 改良」スマホ 三脚 Diestord フレキシブル ミニ三脚 カメラ 三脚 一眼レフ三脚ホルダー iPhone/Android/一眼レフ/ミラーレス/デジタルカメラ/ビデオカメラ三脚 くねくね三脚 自由雲台 軽量 【リモコン付き】 | Diestord | 卓上三脚・ミニ三脚

こちらは、Handycam の固定用と手牌カメラ用のクイックシューに分けて利用しています。

www.amazon.co.jp

こちらに上述の手牌カメラ用クイックシューを取り付けました。

liveshell.cerevo.com

LiveShell PRO です。YouTube や Twitch などに直接配信もできるすぐれものです。

Buy a Raspberry Pi 4 Model B – Raspberry Pi

ラズパイです。LANケーブルを壁や天井に這わせられるなら必要ないですね。

おわりに

最後に今年の私と whywaita の成績を見ておきましょう。

f:id:gurapomu:20211208145445p:plain

来年はツキがまわってくるといいですね!!

明日の担当は id:hogashi さんです!

*1:私は寝るときは布団派なのでベッドはありません

*2:普段は麻雀卓は畳んでウォークインの中にしまってあります

*3:取り扱い注意

dcgm-exporter で Kubernetes 上の GPU ノードを監視する

はじめに

この記事は CyberAgent Developers Advent Calendar 2020 14日目の記事です。(前日の記事はまだ上がっていないようです・・・)

adventar.org

背景

私が所属する AI事業本部 Strategic Infrastructure Agency (以下 SIA) では現在 NVIDIADGX A100 という GPU サーバーを導入し、プライベートクラウドサービスとして提供するために検証を行っています。

DGX A100 のパフォーマンス検証結果は SIA に来てくれたインターン生が執筆したこちらの記事をご覧ください。

[https://www.nvidia.com/ja-jp/data-center/dgx-a100/:embed:cite]

本記事では、 SIA が提供する GPU as a Service や新たにリリースされる SIA AI Platform で DGX A100 を提供するための監視方法を紹介します。

環境

SIA が提供する GPUaaS は Kubernetes 上に構築されており、その Kubernetes 上の DGX A100 に pod がスケジュールされることで GPU を利用してもらうことになります。

構成のイメージ図は以下の画像になります。

f:id:gurapomu:20201214143636p:plain

ということで Kubernetes Node の中から GPU Node を選択して dcgm-exporter をデプロイすることになります。

デプロイ

dcgm-exporter

NVIDIA/gpu-monitoring-toolsリポジトリを参考に、Daemonset の manifest に tolerations と nodeSelector を追記します。

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: "dcgm-exporter"
  namespace: "monitoring"
  labels:
    app.kubernetes.io/name: "dcgm-exporter"
    app.kubernetes.io/version: "2.1.1"
spec:
  updateStrategy:
    type: RollingUpdate
  selector:
    matchLabels:
      app.kubernetes.io/name: "dcgm-exporter"
      app.kubernetes.io/version: "2.1.1"
  template:
    metadata:
      labels:
        app.kubernetes.io/name: "dcgm-exporter"
        app.kubernetes.io/version: "2.1.1"
      name: "dcgm-exporter"
    spec:
      tolerations:
      - key: <gpu-node-taint-key>
        value: <gpu-node-taint-value>
        effect: "NoSchedule"
      containers:
      - image: "nvidia/dcgm-exporter:2.0.13-2.1.1-ubuntu18.04"
        env:
        - name: "DCGM_EXPORTER_LISTEN"
          value: ":9400"
        - name: "DCGM_EXPORTER_KUBERNETES"
          value: "true"
        name: "dcgm-exporter"
        ports:
        - name: "metrics"
          containerPort: 9400
        securityContext:
          runAsNonRoot: false
          runAsUser: 0
        volumeMounts:
        - name: "pod-gpu-resources"
          readOnly: true
          mountPath: "/var/lib/kubelet/pod-resources"
      volumes:
      - name: "pod-gpu-resources"
        hostPath:
          path: "/var/lib/kubelet/pod-resources"
      nodeSelector:
        <gpu-node-label-key>: <gpu-node-label-value>
---
kind: Service
apiVersion: v1
metadata:
  name: "dcgm-exporter"
  namespace: "monitoring"
  labels:
    app.kubernetes.io/name: "dcgm-exporter"
    app.kubernetes.io/version: "2.1.1"
spec:
  selector:
    app.kubernetes.io/name: "dcgm-exporter"
    app.kubernetes.io/version: "2.1.1"
  ports:
  - name: "metrics"
    port: 9400

適切な tolerations と nodeSelector を設定することで GPU Node に dcgm-exporter の pod が起動します。

ServiceMonitor

Prometheus は prometheus-operator によって管理されているため dcgm-exporter の ServiceMonitor を作成することで dcgm-exporter を監視対象として追加します。ServiceMonitor も NVIDIA/gpu-monitoring-tools を参考にします。

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: "dcgm-exporter"
  namespace: "monitoring"
  labels:
    app.kubernetes.io/name: "dcgm-exporter"
    app.kubernetes.io/version: "2.1.1"
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: "dcgm-exporter"
      app.kubernetes.io/version: "2.1.1"
  endpoints:
  - port: "metrics"
    path: "/metrics"

metrics

pod が正常に起動しているか確認します。

$ kubectl -n monitoring port-forward daemonset/dcgm-exporter 9400 &
$ curl localhost:9400/metrics
# HELP DCGM_FI_DEV_SM_CLOCK SM clock frequency (in MHz).
# TYPE DCGM_FI_DEV_SM_CLOCK gauge
# HELP DCGM_FI_DEV_MEM_CLOCK Memory clock frequency (in MHz).
# TYPE DCGM_FI_DEV_MEM_CLOCK gauge
# HELP DCGM_FI_DEV_MEMORY_TEMP Memory temperature (in C).
# TYPE DCGM_FI_DEV_MEMORY_TEMP gauge
# HELP DCGM_FI_DEV_GPU_TEMP GPU temperature (in C).
# TYPE DCGM_FI_DEV_GPU_TEMP gauge
# HELP DCGM_FI_DEV_POWER_USAGE Power draw (in W).
# TYPE DCGM_FI_DEV_POWER_USAGE gauge
# HELP DCGM_FI_DEV_TOTAL_ENERGY_CONSUMPTION Total energy consumption since boot (in mJ).
# TYPE DCGM_FI_DEV_TOTAL_ENERGY_CONSUMPTION counter
# HELP DCGM_FI_DEV_PCIE_TX_THROUGHPUT Total number of bytes transmitted through PCIe TX (in KB) via NVML.
# TYPE DCGM_FI_DEV_PCIE_TX_THROUGHPUT counter
# HELP DCGM_FI_DEV_PCIE_RX_THROUGHPUT Total number of bytes received through PCIe RX (in KB) via NVML.
# TYPE DCGM_FI_DEV_PCIE_RX_THROUGHPUT counter
# HELP DCGM_FI_DEV_PCIE_REPLAY_COUNTER Total number of PCIe retries.
# TYPE DCGM_FI_DEV_PCIE_REPLAY_COUNTER counter
# HELP DCGM_FI_DEV_GPU_UTIL GPU utilization (in %).
# TYPE DCGM_FI_DEV_GPU_UTIL gauge
# HELP DCGM_FI_DEV_MEM_COPY_UTIL Memory utilization (in %).
# TYPE DCGM_FI_DEV_MEM_COPY_UTIL gauge
# HELP DCGM_FI_DEV_ENC_UTIL Encoder utilization (in %).
# TYPE DCGM_FI_DEV_ENC_UTIL gauge
# HELP DCGM_FI_DEV_DEC_UTIL Decoder utilization (in %).
# TYPE DCGM_FI_DEV_DEC_UTIL gauge
# HELP DCGM_FI_DEV_XID_ERRORS Value of the last XID error encountered.
# TYPE DCGM_FI_DEV_XID_ERRORS gauge
# HELP DCGM_FI_DEV_POWER_VIOLATION Throttling duration due to power constraints (in us).
# TYPE DCGM_FI_DEV_POWER_VIOLATION counter
# HELP DCGM_FI_DEV_THERMAL_VIOLATION Throttling duration due to thermal constraints (in us).
# TYPE DCGM_FI_DEV_THERMAL_VIOLATION counter
# HELP DCGM_FI_DEV_SYNC_BOOST_VIOLATION Throttling duration due to sync-boost constraints (in us).
# TYPE DCGM_FI_DEV_SYNC_BOOST_VIOLATION counter
# HELP DCGM_FI_DEV_BOARD_LIMIT_VIOLATION Throttling duration due to board limit constraints (in us).
# TYPE DCGM_FI_DEV_BOARD_LIMIT_VIOLATION counter
# HELP DCGM_FI_DEV_LOW_UTIL_VIOLATION Throttling duration due to low utilization (in us).
# TYPE DCGM_FI_DEV_LOW_UTIL_VIOLATION counter
# HELP DCGM_FI_DEV_RELIABILITY_VIOLATION Throttling duration due to reliability constraints (in us).
# TYPE DCGM_FI_DEV_RELIABILITY_VIOLATION counter
# HELP DCGM_FI_DEV_FB_FREE Framebuffer memory free (in MiB).
# TYPE DCGM_FI_DEV_FB_FREE gauge
# HELP DCGM_FI_DEV_FB_USED Framebuffer memory used (in MiB).
# TYPE DCGM_FI_DEV_FB_USED gauge
# HELP DCGM_FI_DEV_ECC_SBE_VOL_TOTAL Total number of single-bit volatile ECC errors.
# TYPE DCGM_FI_DEV_ECC_SBE_VOL_TOTAL counter
# HELP DCGM_FI_DEV_ECC_DBE_VOL_TOTAL Total number of double-bit volatile ECC errors.
# TYPE DCGM_FI_DEV_ECC_DBE_VOL_TOTAL counter
# HELP DCGM_FI_DEV_ECC_SBE_AGG_TOTAL Total number of single-bit persistent ECC errors.
# TYPE DCGM_FI_DEV_ECC_SBE_AGG_TOTAL counter
# HELP DCGM_FI_DEV_ECC_DBE_AGG_TOTAL Total number of double-bit persistent ECC errors.
# TYPE DCGM_FI_DEV_ECC_DBE_AGG_TOTAL counter
# HELP DCGM_FI_DEV_RETIRED_SBE Total number of retired pages due to single-bit errors.
# TYPE DCGM_FI_DEV_RETIRED_SBE counter
# HELP DCGM_FI_DEV_RETIRED_DBE Total number of retired pages due to double-bit errors.
# TYPE DCGM_FI_DEV_RETIRED_DBE counter
# HELP DCGM_FI_DEV_RETIRED_PENDING Total number of pages pending retirement.
# TYPE DCGM_FI_DEV_RETIRED_PENDING counter
# HELP DCGM_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_TOTAL Total number of NVLink flow-control CRC errors.
# TYPE DCGM_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_TOTAL counter
# HELP DCGM_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_TOTAL Total number of NVLink data CRC errors.
# TYPE DCGM_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_TOTAL counter
# HELP DCGM_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_TOTAL Total number of NVLink retries.
# TYPE DCGM_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_TOTAL counter
# HELP DCGM_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_TOTAL Total number of NVLink recovery errors.
# TYPE DCGM_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_TOTAL counter
# HELP DCGM_FI_DEV_NVLINK_BANDWIDTH_TOTAL Total number of NVLink bandwidth counters for all lanes
# TYPE DCGM_FI_DEV_NVLINK_BANDWIDTH_TOTAL counter


DCGM_FI_DEV_SM_CLOCK{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 210
DCGM_FI_DEV_MEM_CLOCK{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 1215
DCGM_FI_DEV_MEMORY_TEMP{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 25
DCGM_FI_DEV_GPU_TEMP{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 26
DCGM_FI_DEV_POWER_USAGE{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 42.775000
DCGM_FI_DEV_TOTAL_ENERGY_CONSUMPTION{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 19160364272
DCGM_FI_DEV_PCIE_TX_THROUGHPUT{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 36296895
DCGM_FI_DEV_PCIE_RX_THROUGHPUT{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 13653238
DCGM_FI_DEV_PCIE_REPLAY_COUNTER{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 0
DCGM_FI_DEV_GPU_UTIL{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 9223372036854775794
DCGM_FI_DEV_MEM_COPY_UTIL{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 9223372036854775794
DCGM_FI_DEV_ENC_UTIL{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 9223372036854775794
DCGM_FI_DEV_DEC_UTIL{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 9223372036854775794
DCGM_FI_DEV_XID_ERRORS{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 0
DCGM_FI_DEV_POWER_VIOLATION{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 0
DCGM_FI_DEV_THERMAL_VIOLATION{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 0
DCGM_FI_DEV_SYNC_BOOST_VIOLATION{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 0
DCGM_FI_DEV_BOARD_LIMIT_VIOLATION{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 0
DCGM_FI_DEV_LOW_UTIL_VIOLATION{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 0
DCGM_FI_DEV_RELIABILITY_VIOLATION{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 0
DCGM_FI_DEV_FB_FREE{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 9223372036854775795
DCGM_FI_DEV_FB_USED{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 9223372036854775795
DCGM_FI_DEV_ECC_SBE_VOL_TOTAL{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 0
DCGM_FI_DEV_ECC_DBE_VOL_TOTAL{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 0
DCGM_FI_DEV_ECC_SBE_AGG_TOTAL{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 0
DCGM_FI_DEV_ECC_DBE_AGG_TOTAL{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 0
DCGM_FI_DEV_RETIRED_SBE{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 9223372036854775794
DCGM_FI_DEV_RETIRED_DBE{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 9223372036854775794
DCGM_FI_DEV_RETIRED_PENDING{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 9223372036854775794
DCGM_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_TOTAL{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 9223372036854775794
DCGM_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_TOTAL{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 9223372036854775794
DCGM_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_TOTAL{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 9223372036854775794
DCGM_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_TOTAL{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 9223372036854775794
DCGM_FI_DEV_NVLINK_BANDWIDTH_TOTAL{gpu="0", UUID="hoge-fuga-piyo",container="",namespace="",pod=""} 9223372036854775794
[以下略]

正常に起動していることが確認できました。

Prometheus

続いて、Prometheus 経由で正常に監視できているかを確認します

$ kubectl -n monitoring port-forward svc/prometheus-k8s 9090

f:id:gurapomu:20201214171549p:plain

prometheus-operator の ServiceMonitor は機能しているようです。

Grafana

同じく NVIDIA/gpu-monitoring-toolsDashboard を利用します。

f:id:gurapomu:20201214181107p:plain

AlertManager

後日追記します。

まとめ

アラート設定など未完な部分があるので後日追記させていただきます。

現在、最新の 2.1.1 が DGX A100 の nvidia-docker 上で動かず 1.7.2 を利用しています。その影響か GPU Core と Memory の Utilization が正常に取得できないという問題に遭遇しており、現在 issue を立てていますが17日間音沙汰がなく困っています・・・

おわりに

明日はイワケンさんの担当になります!

Kubernetes と HPA と VPA と ClusterAutoscaler

はじめに

この記事は、CyberAgent 20新卒 エンジニア Advent Calendar 2019の15日目の記事です。

adventar.org

自己紹介

AI事業本部の SIA で内定者アルバイトをしています、げんば (GB) といいます。

インターネットでは gurapomu という名前で活動しています。Twitter やっていますが技術的なことはほぼつぶやかないのでご注意ください。

目次

  • Kubernetes とは
  • PodAutoscale
  • HPA と VPA の併用
    • HPA external metrics and VPA (予定)
  • VPA と ClusterAutoscaler の併用

Kubernetes とは

みなさんご存知でしょうし細かい説明は省略します。一言でいうと Google がつくったコンテナオーケストレーターです。「クバネティス」とか「クーベネティス」とかいろいろな読まれ方をしています。名称が長いので k8s という略称があります。k と s の間が8文字であることに由来しているようです。自分自身はずっと「けーはちえす」と言っていましたがあんまりこう言ってる人はいなさそうです。海外では「k-eights」という読まれ方は結構されているようです。1

名前すら初めて聞いたぞ、という方には申し訳ありませんがここからの内容は少しは Kubernetes いじったことあるぞ、といった人以上を対象としたお話になります。

Pod Scaling

今回の主題は pod の autoscaling についてです。Kubernetes では HPA と VPA2 という2種類の scale 方法が用意されています。それぞれについて軽く説明しておきたいと思います。

HPA (Horizontal Pod Autoscaler)

horizontal は和訳すると水平という意味ですので水平にポッドをスケールする機能ということになります。水平スケールとはスケールアウトのことを指し、pod 自体の数を増減することで調整を行うという機能ということです。

VPA (Vertical Pod Autoscaler)

vertical は和訳すると垂直という意味です。ですので VPA は 垂直スケール、すなわちポッド自体の大きさを変更することによって調整を行う機能になります。水平と垂直の覚え方に関しては諸説ありますが自分としてはどれも納得が行っていないので読者の課題とします。

f:id:gurapomu:20191204180809p:plain

HPA と VPA の併用

それでは実際にこれらを導入してみます。VPA コンポーネントについてはそこそこ日本語記事がありますのでそちらを参照されるといいかと思います。

以下のyamlが実際にデプロイしたマニフェストです。公式の github にあるマニフェストを参考に HPA を追加で定義したものになります。

autoscaler/hamster.yaml at master · kubernetes/autoscaler · GitHub

---
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
  name: hamster-hpa
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: hamster
  minReplicas: 1
  maxReplicas: 20
  metrics:
  - type: Resource
    resource:
      name: cpu
      targetAverageUtilization: 50
---
apiVersion: "autoscaling.k8s.io/v1beta2"
kind: VerticalPodAutoscaler
metadata:
  name: hamster-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: hamster
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.5
        ports:
        - containerPort: 80

デプロイしたポッドでは nginx が立ちあがります。

こちらに何らかの方法で負荷をかけていきます。今回の実験環境では LOCUST による負荷テストを行いました。

結果

負荷テストを行った結果、先に HPA が機能し十分にスケールされ VPA が機能しないという減少が起こりました。HPA によってポッドが 20 個まで増加した結果、個々のポッドの負荷は大きくならずにスケールアップの必要性がないと判断されるというロジックです。

VPA の README.md を読むとこんなことが書いてあります。

Vertical Pod Autoscaler should not be used with the Horizontal Pod Autoscaler (HPA) on CPU or memory at this moment. However, you can use VPA with HPA on custom and external metrics.

github.com

そもそも、VPA と HPA を標準で使うべきではなかったみたいです。但し書きとして HPA で外部メトリクスを用いれば良いと書いてあったので、今後検証を行い追記したいと考えています。

VPA と ClusterAutoscaler の併用

今度は ClusterAutoscaler と併用してみる実験です。ClusterAutoscaler については深くは触れませんが簡単にいうと、Kubernetes のノード自体をスケールアウトさせようという機能になります。これによりリソース不足でデプロイできないポッドが発生すると新しいノードがクラスタに参入し、新たにポッドがデプロイできるようになるというメリットが得られます。

クラスタに ClusterAutoscaler を導入し、先程のマニフェストから HPA リソースを削除したものをデプロイし、LOCUST によって負荷をかけました。

結果

結果は以下のとおりです。時間の経過によりノードが作成されて徐々に RPS が上昇していることがわかります。

f:id:gurapomu:20191216141713p:plain

蛇足

蛇足にはなりますが、VPA と ClusterAutoscaler の併用にはうまく動作しないエッジケースが存在します。しかしそれを説明するためには本記事では前提となる VPA の仕組みの解説が足りていないため読者の課題とします。

おわりに

投稿が遅れてしまい申し訳ありません。風邪で稼働できずに予定していた内容も網羅できていないため今後随時追記を行っていく予定です 個々までお読みいただきありがとうございました。


  1. 要出典

  2. 現在アルファ版につき絶賛機能開発中のようです。

Bitcoinのブロックチェーンに任意のデータを刻む

背景

電子の海に己が存在を刻み込むのよ!!

BitcoinのOP_RETURNをつかってブロックチェーンに任意のデータ保存する手法、プログラミング言語ベースで解説されている記事が数個みつけましたが、pubScriptベースで解説されている日本語記事がみつからなかったので書くことにしました。

概要

以下、概要

pubScript

pubScriptについてはこちらを参照してください。

qiita.com

Bitcoin環境の作成

おあつらえ向きのDockerfileがGithubに公開されているのでつかわせてもらいます。

$ git clone https://github.com/kylemanna/docker-bitcoind
$ cd cd docker-bitcoind

bin/btc_initbitcoin.conf として利用されるようになっているので以下のように編集しました。

#!/bin/bash

set -ex

# This shouldn't be in the Dockerfile or containers built from the same image
# will have the same credentials.
if [ ! -e "$HOME/.bitcoin/bitcoin.conf" ]; then
    mkdir -p $HOME/.bitcoin

    echo "Creating bitcoin.conf"

    # Seed a random password for JSON RPC server
    cat <<EOF > $HOME/.bitcoin/bitcoin.conf
testnet=3
rpcallowip=172.17.0.0/16
rpcconnect=127.0.0.1
rpcuser=[user]
rpcpassword=[password]
rpcport=18332
printtoconsole=1
txindex=1
EOF

fi

cat $HOME/.bitcoin/bitcoin.conf

echo "Initialization completed successfully"

testnet=3 を追記してtestnetに接続するようにしています。testnetのrpcportは慣例的に18332を利用するのでこれも変更しました。

dockerイメージをビルドして動かしてみましょう。

$ docker build -t bitcoin .
$ docker run -v $HOME/bitcoin-data:/bitcoin --name=bitcoind-node -d -p 18333:18333 -p 127.0.0.1:18332:18332 bitcoin

18333ポートは他ノードとの通信に利用されるようです。

$HOME/bitcoin-data にはBitcoinのブロックチェーンがダウンロードされるようになっています。2018/2/19 15時現在、testnetのブロックチェーンは15GBほどあります。

以下のコマンドでコンテナにアタッチできます

$ docker exec -i -t bitcoind-node bash

アタッチしたらbitcoin-cliコマンドでブロックの状況を確認してみましょう*1

# root@c4a8538d33c6:~# bitcoin-cli getinfo
{
  "deprecation-warning": "WARNING: getinfo is deprecated and will be fully removed in 0.16. Projects should transition to using getblockchaininfo, getnetworkinfo, and getwalletinfo before upgrading to 0.16",
  "version": 150100,
  "protocolversion": 70015,
  "walletversion": 139900,
  "balance": 1.29998000,
  "blocks": 1283618,
  "timeoffset": 0,
  "connections": 20,
  "proxy": "",
  "difficulty": 953631.231859672,
  "testnet": true,
  "keypoololdest": 1518769536,
  "keypoolsize": 1999,
  "paytxfee": 0.00000000,
  "relayfee": 0.00001000,
  "errors": "Warning: Unknown block versions being mined! It's possible unknown rules are in effect"
}

下準備

早速電子の海に己が存在を刻み込みたいところですが幾つか下準備が必要になります。

まずは手数料の準備です。先程 getinfo によって取得した情報によるとrelayfeeが0.00001000BTC (1000satoshi) となっていますのでこれ以上を用意しておく必要があります。

testnet faucetを探して自分のアドレスに送金しておきましょう。最長でも15~30分くらいで1 confirmされると思います。

さらに1000satoshi以上用意してある場合はお釣りをもらうアドレスも必要ですので作成しておきましょう。

トランザクションの作成

まずはお釣りのトランザクションを作成してしまいます。未使用のトランザクションのIDとお釣りを送る先のアドレスを確認しておきましょう。

# bitcoin-cli listunspent
[
  {
    "txid": "b85859e623a4486f800935ac06814ff879404d18e672322eb5868fd0603677f0",
    "vout": 0,
    "address": "mk1AgTJSJJtaujpEwXMYLGLunRvoWLakXD",
    "account": "",
    "scriptPubKey": "76a91431367d536429a0f8d4e1ccbe0e0086260f83e50388ac",
    "amount": 1.29998000,
    "confirmations": 125,
    "spendable": true,
    "solvable": true,
    "safe": true
  }
]
# bitcoin-cli getaddressesbyaccount ""
[
  "mk1AgTJSJJtaujpEwXMYLGLunRvoWLakXD",
  "mroc2MUN47VWd5YcUYpVvHPYkyCTVxbASJ",
  "n1U1c27rtNGNs5FvBuQ8Eqx4PoHJwX1Y82",
  "n2yqHkko8P9WaevzHrdShp5iwxvJcfH4X3",
  "n3SUf3ePtEzi2MW6DR3JT1ch5waLkZaEta",
  "n45RrVcGXU6ejk4FdTG4vXXyrxkTgVB3Tv",
  "n4YyHACYQCefGf5MoBa8xYDouBnMmiuTgL"
]

1.29998BTCの未使用トランザクションがあったのでこれを使います。このtxidから新しいトランザクションを作成します。アドレスは一番上のものに1.29998BTCあるのでなにもはいっていない2番目のものを使うことにします。

トランザクションの作成には createrawtransaction を使います。送金額はいま持っている1.29998から手数料を引いた1.29997BTCに設定します。

# bitcoin-cli createrawtransaction '
[{"txid": "b85859e623a4486f800935ac06814ff879404d18e672322eb5868fd0603677f0","vout": 0}]
' '
{"mroc2MUN47VWd5YcUYpVvHPYkyCTVxbASJ": 1.29997}
'
0200000001f0773660d08f86b52e3272e6184d4079f84f8106ac3509806f48a423e65958b80000000000ffffffff01c898bf07000000001976a9147bcf88aa523b792fb77cee6f6fc9931189bbfe7f88ac00000000

これでトランザクションが作成されました。細かく中身を見ていきましょう。

02000000          < バージョン
01                < インプットするトランザクションの数
f0773660d08f86b52e3272e6184d4079f84f8106ac3509806f48a423e65958b8
                  < トランザクションID (32bitのリトルエンディアン)
00000000          < Vout
00                < scriptSigの長さ
ffffffff          < シーケンス番号
01                < アウトプットの数
c898bf0700000000  < アウトプットの金額
19                < pubScriptの大きさ
76a9147bcf88aa523b792fb77cee6f6fc9931189bbfe7f88ac
                  < pubScript
                  < (OP_DUP OP_HASH160 7bcf88aa523b792fb77cee6f6fc9931189bbfe7f OP_EQUALVERIFY OP_CHECKSIG)
00000000          < Lock time

ここのトランザクションのアウトプットの数を1増やしてそこにOP_RETURN命令を追加すれば良いでしょう。ということで書き換えたトランザクションが以下のとおりです。

02000000          < バージョン
01                < インプットするトランザクションの数
f0773660d08f86b52e3272e6184d4079f84f8106ac3509806f48a423e65958b8
                  < トランザクションID
00000000          < Vout
00                < scriptSigの長さ
ffffffff          < シーケンス番号
02                < アウトプットの数
c898bf0700000000  < アウトプットの金額(1)
19                < pubScriptの大きさ(1)
76a9147bcf88aa523b792fb77cee6f6fc9931189bbfe7f88ac
                  < pubScript(1)
                  < (OP_DUP OP_HASH160 7bcf88aa523b792fb77cee6f6fc9931189bbfe7f OP_EQUALVERIFY OP_CHECKSIG)
0000000000000000  < アウトプットの金額(2)
1a                < pubScriptの大きさ(2)
6a18e4bfbae3818ce38190e38289e381bde38280e381a0efbc81
                  < pubScript(2)
                  < (OP_RETURN e4bfbae3818ce38190e38289e381bde38280e381a0efbc81)
00000000          < Lock time

補足に(2)と書いてある部分が追記したところです。まずアウトプットの金額は0ですので0を埋めてpubScriptの大きさを1byteで記述します。OP_RETURNのopcodeは0x6aですので、これとデータのサイズを示す1byteと実データのサイズを含めた数字を入れましょう。 今回突っ込むデータは24byteだったのでpubScriptの大きさは0x1aとなりました。

さて、これで大丈夫そうかデコードしてみます。

# bitcoin-cli decoderawtransaction
{
  "txid": "c4fb7e7af51880753fcd2a630d8355a81069d74474a497a76df80aea0d65e5d5",
  "hash": "c4fb7e7af51880753fcd2a630d8355a81069d74474a497a76df80aea0d65e5d5",
  "version": 2,
  "size": 120,
  "vsize": 120,
  "locktime": 0,
  "vin": [
    {
      "txid": "b85859e623a4486f800935ac06814ff879404d18e672322eb5868fd0603677f0",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 1.29997000,
      "n": 0,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 7bcf88aa523b792fb77cee6f6fc9931189bbfe7f OP_EQUALVERIFY OP_CHECKSIG",
        "hex": "76a9147bcf88aa523b792fb77cee6f6fc9931189bbfe7f88ac",
        "reqSigs": 1,
        "type": "pubkeyhash",
        "addresses": [
          "mroc2MUN47VWd5YcUYpVvHPYkyCTVxbASJ"
        ]
      }
    },
    {
      "value": 0.00000000,
      "n": 1,
      "scriptPubKey": {
        "asm": "OP_RETURN e4bfbae3818ce38190e38289e381bde38280e381a0efbc81",
        "hex": "6a18e4bfbae3818ce38190e38289e381bde38280e381a0efbc81",
        "type": "nulldata"
      }
    }
  ]
}

2つ目のアウトプットもいい感じにデコードされていますね。

トランザクションの送信

このままではトランザクションコードを作成しただけでブロックチェーンネットワークに反映されないので、これを送信していきます。

まずは署名します。

# bitcoin-cli signrawtransaction 0200000001f0773660d08f86b52e3272e6184d4079f84f8106ac3509806f48a423e65958b80000000000ffffffff02c898bf07000000001976a9147bcf88aa523b792fb77cee6f6fc9931189bbfe7f88ac00000000000000001a6a18e4bfbae3818ce38190e38289e381bde38280e381a0efbc8100000000
{
  "hex": "0200000001f0773660d08f86b52e3272e6184d4079f84f8106ac3509806f48a423e65958b80000000000ffffffff02c898bf07000000001976a9147bcf88aa523b792fb77cee6f6fc9931189bbfe7f88ac00000000000000001a6a18e4bfbae3818ce38190e38289e381bde38280e381a0efbc8100000000",
  "complete": true
}

署名済みのhexコードがでてきたのでこれを送信しましょう。

# bitcoin-cli sendrawtransaction 0200000001f0773660d08f86b52e3272e6184d4079f84f8106ac3509806f48a423e65958b80000000000ffffffff02c898bf07000000001976a9147bcf88aa523b792fb77cee6f6fc9931189bbfe7f88ac00000000000000001a6a18e4bfbae3818ce38190e38289e381bde38280e381a0efbc8100000000
fb16f47bc12f490bb243dfff195ef36610ec1996a46584d11fb33393fa7a6b16

最後に表示されているのが送信されたトランザクションのtxidになります。念のため確認してみましょう。

# bitcoin-cli gettransaction fb16f47bc12f490bb243dfff195ef366
{
  "amount": 0.00000000,
  "fee": -0.00001000,
  "confirmations": 1,
  "blockhash": "000000000000016bf4956eb603bd972e0271d41873c59480cce0becc1caa4724",
  "blockindex": 39,
  "blocktime": 1519024661,
  "txid": "fb16f47bc12f490bb243dfff195ef36610ec1996a46584d11fb33393fa7a6b16",
  "walletconflicts": [
  ],
  "time": 1519024410,
  "timereceived": 1519024410,
  "bip125-replaceable": "no",
  "details": [
    {
      "account": "",
      "address": "mroc2MUN47VWd5YcUYpVvHPYkyCTVxbASJ",
      "category": "send",
      "amount": -1.29997000,
      "label": "",
      "vout": 0,
      "fee": -0.00001000,
      "abandoned": false
    },
    {
      "account": "",
      "category": "send",
      "amount": 0.00000000,
      "vout": 1,
      "fee": -0.00001000,
      "abandoned": false
    },
    {
      "account": "",
      "address": "mroc2MUN47VWd5YcUYpVvHPYkyCTVxbASJ",
      "category": "receive",
      "amount": 1.29997000,
      "label": "",
      "vout": 0
    }
  ],
  "hex": "0200000001f0773660d08f86b52e3272e6184d4079f84f8106ac3509806f48a423e65958b8000000006b483045022100d554d09f60df7a338c5cb272e3772fd67eccca032359c1fb77f93e5c584daaca0220132cac750d8314e4ead8fccd3bbc1e15f2e9f4b99c3af18802a7cd206607de1d01210283880535cfb90692bce2a7ec51840691a8b8cd9295983cca3ed2e0c6f77396dfffffffff02c898bf07000000001976a9147bcf88aa523b792fb77cee6f6fc9931189bbfe7f88ac00000000000000001a6a18e4bfbae3818ce38190e38289e381bde38280e381a0efbc8100000000"
}

送信できているみたいなのでconfirmされるまで待ってブロックエクスプローラーを確認してみます。今回のトランザクションはこちらにのっています。

Bitcoin Transaction fb16f47bc12f490bb243dfff195ef36610ec1996a46584d11fb33393fa7a6b16

f:id:gurapomu:20180219162645p:plain

自分の入力したデータがブロックチェーンに残っていることが確認できました!!!

*1:getinfoはもう使えなくなるらしいですね

CrystalのプログラムをRaspberry pi上で動かす

この記事は MCC Advent Calendar 2017 - Adventar の7日目の記事です。

早くも3投稿目になりますががんばって行きましょう。

パッと記事の投稿予定をみると技術系の記事が多かったので同調圧力に負けてそういった記事を書いてみようと思います。

背景

ラズパイのGPIOとマイコンを連携(もしくはGPIOをそのまま使うなど)して、センサーから色々データをとったり家電を操作しようということ試みる。

インターフェースとしてWebサーバーを置こうということを思い立ったが、Railsとかいじるのも癪なのでなんか面白そうなWebフレームワークを探し始める。

Rubyライクな「Crystal」という言語でつくられた「Amethyst」というフレームワークを見つけたので使ってみようということになった。

そうメジャーな言語ではないと思うがCrystalについては最近いろいろな人がいじって話題にしているのでそちらを参考にしてほしい。

ポストRubyだなんだといっているがそういうのには興味なくて、使いやすい場面で使ってくれといったかんじ*1

問題点

紆余曲折*2あって、とりあえずラズパイにCrystalのコンパイラを乗せることにするがここで問題が発生する。

ARM向けのバイナリがない

さらに

コンパイラはCrystalで記述されている

対処

ザッと調べてみたところ、以前に「ARM向けコンパイラをつくる」というissueが立っていた。

このissueは「クロスコンパイルオプションを実装する」というissueにmergeされていた。

つまり、クロスコンパイルで自分でARM向けバイナリをビルドしろということか・・・

# helloworld.cr
puts "Hello world!"
$ crystal build --cross-compile -D arm --target=arm-unknown-linux-gnueabihf helloworld.cr --release --mcpu=arm1176jzf-s

今回つかったのはRaspberry pi zeroでCPUがARM1176JZF-Sですが、2や3ではCortexだったと思うのでまたオプションが変わってくるとおもいます。(試していないので性格なことはわかりませんが)

コンパイルすると、ターゲット環境で以下のコマンドを実行しろよ、といった雰囲気の文字列が表示されます

cc 'helloworld.o' -o 'helloworld'  -rdynamic  -lpcre -lgc -lpthread /usr/local/Cellar/crystal-lang/0.23.1_3/src/ext/libcrystal.a -levent -lrt -ldl -L/usr/lib -L/usr/local/lib

なるほど、ターゲット環境にもCrystalのソースはあったほうがいいわけだな。

いい感じにgit cloneして先程のコマンドを実行したところ実行形式バイナリがポンと吐かれました

$ ./helloworld
Hello world!

やりました。

まとめ

時間がなくてなんとかHelloWorldをするところまでしかこぎつけられませんでしたが、いい感じにやればいい感じに行くんじゃないかなという気がしています(がどうなんでしょうか)

なにはともあれ近いうちにAmethystを動かすところまで漕ぎ着けたいです。


明日の予定はありません!!!!各位!!!

adventar.org

*1:といった点ではWebに静的型付き言語はどうなのかと思うところもあるが...

*2:かどうかは諸説ある

リアルお料理対決をした話

この記事は MCC Advent Calendar 2017 - Adventar の4日目の記事です。


料理とは 果てなき荒野そのものである

美味しさも不味さも、数限りなく点在する荒野……!

f:id:gurapomu:20171204192830p:plain

背景

先日、スッと合宿所に行ってみたら、料理勝負などという面白そうなことをやっていたので参加してきました。

開始

形式は団体戦で1チーム5,6人で3チームに別れて勝負をすることになりました。

お題はホットプレートを使った料理ということで、自分のチームは餃子をつくることになりました。最終的な料理名は「特製!和風餃子」というところにまとまっています。

材料

だいたいの材料は以下のとおりです。餃子100個分の分量になります。

  • 餃子の皮 100枚
  • 豚ひき肉 300~400g
  • 白菜 1/2~1/4玉(1/2では多いが1/4では少し足りない気がする)
  • 大葉 10枚
  • 干し椎茸 1パック
  • 醤油
  • ほんだし
  • ごま油
  • (おろし生姜)

当日、おろし生姜を入れる予定だったのですがすっかり買うのを忘れていました。なんとかなりましたが、入れたほうが味にまとまりが出るはずです。

調理

まずは、干し椎茸を水につけて戻しておきましょう。戻すのに使った水は、タレを作るのに使うので絶対に捨ててはいけません!

次に、タネを作っていきます。まずは白菜を刻みます。大きさはお好みですが食感が欲しい人は粗みじん切り(だいたい3~4mm角程度)にしておきましょう。大葉は横に細く切っていくと雰囲気が出て良いです。

材料を切り終わったら用意した材料を、餃子の皮を除きすべて混ぜ合わせてください。さっき戻したしいたけも忘れずにね!

タネが出来たら、餃子の皮で包んでいきます。料理の味というのは良くも悪くもビジュアルによって左右されがちです。美味しく味わってもらうにはやはりきれいに包んだほうが良いでしょう。コツとしては、皮の片側のみを折り込んで包んでいくことです。

さて、餃子を包み終わったらホットプレートを温めます。230~240度に設定してください。(ホットプレートって温度が数字で設定できるのでコンロより定量的に説明しやすいですよね)十分に鉄板が温まったら餃子を素早く乗せましょう。ジージーと焼ける音がしたら熱湯を注いで蓋をします。このとき、お湯はだいたい餃子の1/5~1/6が浸かるくらいが良いと思います。

水分を飛ばす間に、タレを作ってしまいましょう。これは簡単です。最初にしいたけを戻すのに使った水にほんだしを加えます。(旨味の相乗効果でトリプルパンチです)さらに醤油をくわえて味をつけます。少しずつ加えて、塩気はお好みで調整してみてください。

鉄板にいれたお湯がなくなったらいよいよ仕上げです。蓋を取りましょう。焦げ目はお好みですが、個人的には和風餃子にはあまり焦げはない方がいい気がします。お好みのところで火をとめて完成です!

実食

しいたけやほんだし、大葉の風味が和風にまとまって素晴らしい出来だったともいます。もう2つのチームは「餃子チーズタッカルビ」と「りんご入りホットケーキ」をつくってくれました。どちらも美味しく、大満足だったと思います。

f:id:gurapomu:20171205092259j:plain

まとめ

そういえば、お料理対決とかいいつつ勝負をつけてなかったなーと思います。まあおいしかったのでいいか。

自分が写真とってなかったのも心残りですね。当日参加して、もし写真撮っている人がいれば、私宛に送ってくれればこの記事が華やかになるので是非よろしくお願いします。


明日は@GEN52462138くんです!よろしくお願いします!!!

TUATMCC 2017の総括

この記事は、MCC Advent Calendar 2017 - Adventar 1日目の記事です。


皆さんおはようございます.

TUATMCC,元部長のぐらぽむでございます.

本日は,2017年ももう12月ということで,少し早いですが2017年のMCCの総括をしていきたいと思います.

後輩の皆には,ぜひこの記事を来年提出する活動報告書等に活用していただければと思います.


1月

ICTSC7の予選に出ていました.HTML/CSS問題を説いていたんだけどunicodeの半角スペースが紛れ込んでいてキレた思い出.個人的には色々あって忙殺されていました.

2月

MCC初の合宿に行きました.LT大会とハッカソンをやって酒をのんで寝たのでもう最高だった思い出です.

3月

ICTSC7の本選に出場していました.ぐわーーっとやったけど新人賞(総合4位)でしたね.悔しい.ちなみに予選順位は2位でした:thinking_face:

春季休業中なので他には特になにもない気がします.

4月

新入生歓迎シーズンでしたね.今年は新入部員が多かった気がするし,現在残っている人間も例年より多い気がするので後輩諸君にはぜひ大事にしていってもらいたいです.

5月

新歓LTをやりました.みんなそれぞれユニークな話題で興味深かったです.ちなみに自分はPPTをつかったクソアイコンの作り方と野球の話をしました.

それから,各種講習会をいろいろやりましたね.ありすぎてわけわからないことになりかけてたけど,参加してくださった方々ありがとうございました,開催してくださった方々お疲れ様でした.経験を活かして,来年は是非教える立場で,というのも面白いと思います.

6月

めちゃくちゃ遅くなったけど確定新歓をやりました.寿司とピザを食ってお話をするだけの会でしたが...体調不良で途中抜けして申し訳なかったです.

7月

学内向けLT大会を開催しました.主に自分のコネクションを使ってでしたが,サークルというくくりを抜けて専門外の人にも情報発信する機会ができてよかったのではないかと思っています.是非第2回も開催したい!

それから,ICPC国内予選にも出場しました.MCCからは3チーム出ましたが,一番成績の良かったチームは大学別順位で2位を記録していました.つくば大会,タイ大会も近くに控えているので是非頑張って欲しいですね...!

8月

MCC夏合宿を行いました.花火が見れる部屋でとてもキレイだったとのことでした.一方では地下室にこもってハッカソン中「なんか外バンバンうるせえな」「花火じゃん,風情もへったくれもねえな」という一幕もありました...

それからICTSC8にも出場しました.4人エントリーしたはずなのに予選を解きに来たのは自分含めて2人という惨劇.「これは予選敗退ですね」と言っていたものの,滑り込みセーフで本選出場,ですが残念ながら入賞には至りませんでした.総合順位はたぶん5か6位くらいだったと思います.無念

9月

ツイッターとかを見返しましたが,MCCっぽいイベントは何もなかったです.

10月

こちらも何もなさそう.MCC秋やる気あるの??????

11月

農学部学祭に出展しましたね.いろんなゲームを展示したり風船を配布したり,子供に大人気だったなーというイメージです.

まとめ

去年に比べて何かが大きく変わった一年だったと思います.合宿を始めたり,学内向けのLT大会をやってみたり,春の講習会を増やしてみたり.

2017年もいよいよあと1ヶ月となりましたが,頑張っていきましょう.

あ,今年こそアドベントカレンダー完走しましょうね!!!!

 

明日の記事を書く人は...いません! おい!!!!!!!!!!