プログラミングテストの機能を作りたいの続き

ネットにアクセスするrubyコードnet.rb

require 'net/http'

Net::HTTP.get_print 'example.com', '/'

これをコンテナ内で実行する。

$ docker run --rm -ti -w /tmp -v /Users/komagata/dev/src/github.com/fjordllc/drill-sergeant/tmp:/tmp/program ruby ruby /tmp/program/net.rb 
<!doctype html>
<html>
<head>
    <title>Example Domain</title>
(略)

ネットをnoneにして実行する。

$ docker run --net=none --rm -ti -w /tmp -v /Users/komagata/dev/src/github.com/fjordllc/drill-sergeant/tmp:/tmp/program ruby ruby /tmp/program/net.rb
/usr/local/lib/ruby/3.0.0/net/http.rb:987:in `initialize': Failed to open TCP connection to example.com:80 (getaddrinfo: Temporary failure in name resolution) (SocketError)
    from /usr/local/lib/ruby/3.0.0/net/http.rb:987:in `open'
    from /usr/local/lib/ruby/3.0.0/net/http.rb:987:in `block in connect'
    from /usr/local/lib/ruby/3.0.0/timeout.rb:97:in `block in timeout'
    from /usr/local/lib/ruby/3.0.0/timeout.rb:107:in `timeout'
    from /usr/local/lib/ruby/3.0.0/net/http.rb:985:in `connect'
    from /usr/local/lib/ruby/3.0.0/net/http.rb:970:in `do_start'
    from /usr/local/lib/ruby/3.0.0/net/http.rb:959:in `start'
    from /usr/local/lib/ruby/3.0.0/net/http.rb:490:in `get_response'
    from /usr/local/lib/ruby/3.0.0/net/http.rb:444:in `get_print'
(略)

ネットを遮断した状態でホスト上のプログラムをコンテナ内で実行できた。

sinatra + pumaでリクエストを受けて結果を返すWebサーバーを作れば同時アクセスはpumaが捌き、ファイルの後片付けはdockerがやってくれるだろう。

pumaで同時アクセスされてもいいように被らない一時的なディレクトリを作ってそこにプログラムを置いて実行すれば良さそう。(プログラム名をランダムにすると$0とかがダサくなるからディレクトリの方をランダムな名前にしたい)

次は実行時間を30秒以内とかに制限したい。

競プロのサイトのように入力されたコードを実行して出力が指定のものになってるかどうかをチェックする機能をプログラミングスクールの機能として作りたい。

少なくともrubyとjsは実行できるようにしたい。メンターの@maedanaさんから競プロのジャッジサーバーのOSSであるarrow-judgeを教えてもらった。

なるほど、chroot, cgroup, ulimit等で実行ディレクトリやCPU・メモリといったリソースを制限しているようだ。

ってことはdockerでもできそうだということで調べてみた。

dockerでコンテナから外部へのネットワークアクセスを禁止する

まずは外部ネットワークにアクセスされると危険なので防ぎたい。

$ docker run --rm debian ping komagata.org -c 3
PING komagata.org (151.101.1.195) 56(84) bytes of data.
64 bytes from 151.101.1.195 (151.101.1.195): icmp_seq=1 ttl=37 time=4.34 ms
64 bytes from 151.101.1.195 (151.101.1.195): icmp_seq=2 ttl=37 time=5.27 ms
64 bytes from 151.101.1.195 (151.101.1.195): icmp_seq=3 ttl=37 time=5.32 ms

--- komagata.org ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 6ms
rtt min/avg/max/mdev = 3.698/4.748/5.385/0.748 ms

これが失敗するようにできれば良い。

$ docker run --net=none --rm debian ping komagata.org -c 3
ping: komagata.org: Temporary failure in name resolution

デフォルトでインストールされる3つのネットワークのうちの一つnoneを指定すればあらゆる外部ネットワークアクセスは防げそうだ。

dockerでメモリ使用量を制限する

docker run -m 100m --rm debian ping komagata.org -c 3 
PING komagata.org (151.101.1.195) 56(84) bytes of data.
64 bytes from 151.101.1.195 (151.101.1.195): icmp_seq=1 ttl=37 time=3.70 ms
64 bytes from 151.101.1.195 (151.101.1.195): icmp_seq=2 ttl=37 time=5.16 ms
64 bytes from 151.101.1.195 (151.101.1.195): icmp_seq=3 ttl=37 time=5.39 ms

--- komagata.org ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 6ms
rtt min/avg/max/mdev = 3.698/4.748/5.385/0.748 ms

100Mに制限してみたがどのぐらいが適量かわからない。

続く

あとはコードを楽にcontainerで実行したい。そして標準入力・コマンドライン引数を流し込んで、標準出力・標準エラーが取れればOKだが・・・

もう5月も後半になりますが、新人の方々はもう新しい生活に慣れたでしょうか。すごく良い会社だとしても慣れない最初のうちはしんどいものです。そこで、20代の内に6社以上転職し、そこからはもう数えるのを辞めた・・・ミスターアンカウンタブルこと私komagataが新しい会社に入った時のいつもの気持ちをお伝えしたいと思います。

入社1日目

緊張もありごちゃごちゃ考える余裕は無い。ただ帰宅後どっと疲れている。

入社2日目

道に迷わず出社できる。

入社3日目

これからずっとここに通うのかよ〜

入社した週の週末

1番しんどい。フィジカル・メンタル共に疲れがでかい。ただ、どんなに自分に合ってて良い会社だとしてもいつもこうなので耐える。 友達に愚痴を言えるぐらいであれば割と余裕がある方。

入社してから2週目の週末

最初の週末と同等レベルでしんどい。友達に愚痴を言える気力もなかったら要注意。

入社してから1ヶ月後

もう1ヶ月か〜なんとか1ヶ月経ったな〜という気持ち。まだしんどいが、2週目の週末よりはだいぶマシ。

入社してから1ヶ月半後

楽ではないが、この感じだったら続けられるかもという気持ち。

入社してから2ヶ月後

これはやっていけるわ。という気持ち。

入社してから1年後

過ごしやすいわぁ〜

入社してから1年半後

業務は大体わかった。飽きてきたな・・・

入社してから2年後まで

転職。(振り出しに戻る)

tmux/screen上でのnvimのescapeレスポンスを早くする - 真面目に、強く、上品に

これ!

ずっとneovimでESC押した後の次のキーの認識までのタイミングが長くて、vimのサクサクした操作というメリットがなくなっていました。しかしこの状況を言葉でなんと表現したら良いか難しくてググれず、困っていました。

いつも何か無意識にESCを押した後一瞬待つという謎のワークアラウンド作法が身につくほどでしたが、この度解決しました。ありがとうございます!サイコー!

先週、食中毒になったようで数日間非常に苦しんだ。

もう回復してあとは胃が荒れているぐらいなんだが、吐き気のない生活のなんとすばらしいことか。

おそらくしゃぶしゃぶ食べ放題に行った時の肉か生卵かどちらかに当たったと思うんだが・・・。

肉はしっかり火を通そうと固く決意したし、もう生卵を食べるのが怖くなった。

そういえばこのブログのドメイン(docs.komagata.org)ばかり使っていてkomagata.orgのドメインはだいぶ放置していたのでサイトを作りました。

Google Domainsを使ってるので(?)Firebase Hostingにおきました。

CSSのAnimationはTwitterで@shimewtrさんに教えてもらいました。ありがとうございます。

https://komagata.org

ずっと下記に書いたような問題意識を自分たちのプログラミングスクールに対して持っております。

OSS Gateオンラインワークショップに参加 - komagataのブログ

そこでこんな活動をやってみたらどうかな〜と思っています。(スクール内限定じゃなくてパブリックなワークショップにしたい)

ワークショップ

OSS活動は終わらないネットゲームであり、みんな脳汁を垂れ流して楽しんでおります。しかしそこに辿り着くまでに色々と障壁があり、プログラミングに興味のある人や初心者の方にプログラミングの楽しさを知ってもらうためのワークショップができないかと考えております。(また、OSS活動以外のプログラミングの楽しみもいいと思う)

Joy of Programming(プログラミングの楽しみ)

1回につき1テーマのプログラミングの楽しみについて体験してもらい、みんなで楽しむ。

役に立つとか、勉強になるとかは置いておいて、楽しさを一番重視する。

テーマ1

自分のための小さなスクリプトを作ろう。

~/binとかに置くような自分のためだけのちょっとした便利スクリプトをみんなでかく。

「昼飯をランダムで決めるスクリプト」とか「~/Downloadsディレクトリの中を定期的に削除するスクリプト」とか「平日の10時に自動で勤怠アプリにログインする」スクリプトとかそういうやつです。

テーマ2

基本のアルゴリズムを実装してみよう。現代のプログラミング言語であれば標準ライブラリで備えているような基本的な簡単なアルゴリズムを自分の得意な言語で実装してみる。

テーマ3

フリーソフトウェア運動に参加する。フリーソフトウェアとは何かを学んで入信する。自分の使ってるソフトをフリーソフトウェアに置き換えられないか検討したり、布教活動をする。

テーマ4

Quineを作ってみよう。(説明すると長くなるので省略)

テーマ5

使ったことない言語を使ってみよう。

テーマ6

使ったことないOSを使ってみよう。

テーマ7

競技プログラミングに挑戦しよう

テーマ8

名著を読もう。

みんなで色々な名著を読んできて、大体の内容を話してもらう。他人におすすめする。

テーマ9

ライブラリを作ろう。gemとかnpmとかそういうのの作り方ワークショップ。これができたらOSS活動に進む感じ。

どういうワークショップにするか

1〜3時間ぐらいの長すぎないワークショップにしたい。一回につき1テーマで開催する。色々やってみて評判の良いテーマが絞れたらそれらを繰り返しやる。1 > 3 > 7...とか。

前半は説明をして、後半で手を動かしてやってみる。最初は1人でサポートしきれるぐらいの人数が良いかもしれない。

全体として、Terminalの使い方、簡単なコードが書ける力(どの言語でもいいが)などが必要になる。

Terminalの使い方は(昔に書いた)下記で学べるかもだが、基本的なプログラミングも学べる何かが欲しい。

本当は怖くない 黒い画面入門: https://fjord.jp/kuroigamen.html

初心者向けだけど、プロでもネタのチョイスによってはずっと楽しめる感じにしたい。例えばQuine入門の内容をやるけど、超難しいやつを自分のテーマとして毎回作っても良いみたいな感じ。競プロ入門を毎回やるけど、すげー人が既にいるとか。コミュニティーの中に目指したくなるロールモデルがいるとより良いと思うので。

ちょっとできるように考えてみたいと思います。

OSS Gateオンラインワークショップ2021-03-13にサポーターとして初参加させていただきました。

参加理由

フィヨルドブートキャンプというプログラミングスクールを運営していますが、生徒の方で「頑張って、歯を食いしばって勉強する!」という状態になる方が出てしまうのが常々僕らの取り組みの問題だと感じています。

「プログラミングが面白くてハマってたらスキルが上がっていた」というのが理想です。逆にハマりさえすればあとは勝手に勉強していくので面白さを伝えるのがスクールの一番の目標といっても過言ではありません。

「どうやったらプログラミングの面白さを伝えられるんだろう?」と考えたときに、やはり「プログラミングの楽しさっつったらOSS活動だろう」ということでOSS活動に参加する人を日夜増やし続けているOSS Gateさんのやり方を学びたく、また僕もその活動をしたいと思って参加しました。

OSS活動参加をサポート

今回はビギナーの方が自身で選んだOSSであるApache AirFlowの開発に参加してみるのをサポートしました。(実際は進行役のPiroさんのメンタリングを僕はほとんど聞いてるだけの形ですが🤭)

詳細なメモを取りながらまず自分でインストールしてみる。わかりにくかった部分をIssueフィードバックする。その部分を直すPRを作って送ってみるという一連の流れをやりました。

僕もAirFlowって初めて知りましたし、途中でちょっとしたbashの問題にハマったり、Issueを書く時の適した英語表現など、僕も非常に勉強になりました。

感想

事前に動画で予習してる時から感じてたのですが、非常に実践的で、そして予想以上に手厚くサポートしてもらえるワークショップですごいなと思いました。

まさに今回参加されたビギナーさんは「これだったらこのあと家で一人でもできる」と思ってもらえたんじゃないかと思います。

「ソフトの文句を言う人」から「ソフトの開発者」に半日で変わったのだからすごい進化です。

スクールでの適用に対する問題点

ひるがえって自分の運営するスクールでの適用を考えた時の問題点を考えてみました。

OSSって何?

プログラミングスクールの生徒として考えるとまず、「OSSってなんですか?」という状態の人にはまだ早いということです。

人が作ってる?

「XXX(ソフト・ライブラリ名)がとても便利!こんなのがあるなんて知りませんでした。」

という感想に対して僕が

あるというより誰かが便利に作ってくれたってことなんですよね。」

とコメントをすると

「そうですよね。誰かが作っているんですよね。考えてみたこともなかったです。」

的なやりとりが大体発生し、そこで初めてOSSなどを意識して学習していくことが多いです。まずそこを超えた人(=ソフトのありがたみを感じたことのある人)じゃないと参加が難しいと思いました。

コマンドライン・gitが使えない

また、コマンドライン・gitが使えることも前提となるので、フィヨルドブートキャンプでいえばそれらのカリキュラムを履修した人以降が対象だと思いました。

スクールに適用するなら

OSS GateではOSS活動に参加したことのないプログラマーが対象ですが、フィヨルドブートキャンプの生徒に対して行う(またはプログラミング学習中の人に行う)ならば、「XXXが使える人」「XXXのカリキュラムより先に進んでいる人」などの前提条件を決める必要があるなと感じました。

そして僕の問題意識から考えると、まずはそこに達していない人にプログラミングの楽しさを伝える活動が必要なのかなと思いました。(達してる人はOSS Gateへ!)

ちょっとそういった活動も考えてみたいと思います。

フィヨルドブートキャンプではチャットをSlackからDiscordに移行しようとしています。

DiscordにはSlackのようなReminder機能がメジャーなBotの中には無いので定期的なミーティングのリマインドを簡単に移行することができません。

有名なreminder-botでは「72時間おきにリマインド」のような単純Interval形式しか対応してません。「毎月1日の9時にリマインド」のようなことができないので困ってました。

ブートキャンプでは現在リマインドすべきものは3つしかなく、SlackのようなReminder Botを僕が作るのも面倒なのでCloud Functionsでやってみました。

流れ

Cloud Scheduler -> Pub/Sub -> Cloud Functions -> Discord

Cloud Schedulerでcronと同じインターフェースで時間を指定できるのでjobを作ります。

Image from Gyazo

ターゲットにはHTTPを指定してリクエストを飛ばしたりもできますが、Pub/Subも指定できます。

Pub/Subはややこしいかと思ってたんですが単に名前決めて作るだけでした。

Cloud FunctionsではPub/Subで作ったイベントをSubscriptionしてそのタイミングで実行できます。

コード

Image from Gyazo

require 'functions_framework'
require 'net/http'
require 'json'

FunctionsFramework.cloud_event 'reminder_sub' do |event|
  uri = URI.parse(ENV['WEBHOOK_URL'])
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true
  params = { "content" => "💬 14:00からふりかえりミーティングが 🔈ミーティング チャンネルで始まります。" }
  headers = { "Content-Type" => "application/json" }
  http.post(uri.path, params.to_json, headers)
end

Discordの発言はwebhookにPOSTするだけです。Cloud Schedulerからpayloadに何か値を入れてれば上記のeventの中にそれが(base64でエンコードされて)入っているのでその内容を使って処理を分けたりもできます。(実際のコードでは3種類の通知をそれで出し分けてます。)

最初のテンプレにGemfileも含まれていて、gemを使うのも何にも苦労せずでした。

Image from Gyazo

Cloud Functionsは高度な用途もありますが、こういうふうに週1回しか動かないクソちょっとしたプログラムを動かすにも安くていいなと思います。

フィヨルドブートキャンプでは終盤に生徒の方と一緒になってみんなが使っているEラーニングシステム自体をスクラムで開発するカリキュラムがあります。

そこでのブランチ戦略を最近変えたので生徒の方への説明も兼ねて紹介します。

Image from Gyazo

GitLab Flowです。 

糸冬 わ り

だとあんまりなのでデプロイについても書きます。

(厳密にはpre-productionはなくて、master=唯一のステージングです)

リリース

デプロイはCloud Buildでgit pushをきっかけにmain = ステージング環境、production = 本番環境という具合でデプロイしています。

デプロイは週1回で、毎週水曜日のふりかえりミーティングの後にリリースしています。

master(main)にPRがマージされるとgit-pr-releaseでリリース用のPRが作成されます。

ss

各担当者はステージング環境で動作確認したらここのチェックボックスにチェックを入れます。

ss2

そして各担当者は自分の実装したところをリリース文に書きます。

全部の動作確認が終わっていたらリリースします。(productionブランチにマージする)

Image from Gyazo

本番環境にデプロイされたらDiscordに通知が来るので、各担当者は本番環境で動作確認をして、IssueをCloseします。

最近変えたところ

以前まではGitHub Flowだったんですが、やっぱりいきなり本番にアップされるのは怖いという声もあり、Git Flowを検討していました。

しかし@kakutaniさんからGit Flowは提唱者自身が

「Git FlowはGitHubとかなかった昔に作ったものだから別のFlowがいいよ」

と言っていると聞いてGitLab Flowを見たら良さそうだったので決めました。

みんなでリリース文を書くというのも、誰がどの機能を作ってくれたのか、学習中の方にも伝わって楽しいということで初めてみましたが好評な感じです。

次はmasterをmainに変えると作業をやる予定です。