まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

タグ:scratch

IBM Cloud から提供されている 30 日間無料 Kubernetes サービスIBM Kubernetes Service 、以下 "IKS")環境を使って利用することのできるコンテナイメージを1日に1個ずつ 30 日間連続で紹介していきます。

環境のセットアップや制約事項については Day0 のこちらの記事を参照してください。

Day 19 からはプログラミング・開発系コンテナとその GUI ツールを中心に紹介してます。区切りの Day 20 は Day 19 で紹介した Node-RED と並ぶローコード開発双璧のもう1つ Scratch イメージをデプロイする例を紹介します。
scratch



【イメージの概要】
「子供のプログラミング教育向け」に使われることが多く、子供向けの印象を持っている人がいるかもしれません。ただ実際には他のローコード開発環境と比べても珍しい「キャラクタードリブン」な開発が可能で、画面内(はじめから画面があることが想定されていることがすごいんですけど・・)のキャラクターを「動かし」たり、「ぶつかったら○○をする、と指示」したりしてアプリケーションを作っていきます。キャラクターが存在していることでゲームが作りやすいという特徴もあり、これが子供向けとされている要因の1つかもしれません。

開発は Scratch 財団と MIT(マサチューセッツ工科大学)による共同開発が行われています。


【イメージのデプロイ】
まずはこちらのファイルを自分の PC にダウンロードしてください:
https://raw.githubusercontent.com/dotnsf/yamls_for_iks/main/scratch3.yaml

今回の Scratch も特にパラメータ指定不要で、そのままデプロイすることができます。以下のコマンドを実行する前に Day 0 の内容を参照して ibmcloud CLI ツールで IBM Cloud にログインし、クラスタに接続するまでを済ませておいてください。

そして以下のコマンドを実行します:
$ kubectl apply -f scratch3.yaml

以下のコマンドで Scrach 関連の Deployment, Service, Pod, Replicaset が1つずつ生成されたことと、サービスが 30601 番ポートで公開されていることを確認します:
$ kubectl get all

NAME                            READY   STATUS    RESTARTS   AGE
pod/scratch3-579cb8b666-cpsl4   1/1     Running   0          89s

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
service/kubernetes   ClusterIP   172.21.0.1      <none>        443/TCP          27d
service/scratch3     NodePort    172.21.71.246   <none>        8601:30601/TCP   91s

NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/scratch3   1/1     1            1           91s

NAME                                  DESIRED   CURRENT   READY   AGE
replicaset.apps/scratch3-579cb8b666   1         1         1       92s

この後に実際にサービスを利用するため、以下のコマンドでワーカーノードのパブリック IP アドレスを確認します(以下の例であれば 161.51.204.190):
$ ibmcloud ks worker ls --cluster=mycluster-free
OK
ID                                                       パブリック IP    プライベート IP   フレーバー   状態     状況    ゾーン   バージョン
kube-c3biujbf074rs3rl76t0-myclusterfr-default-000000df   169.51.204.190   10.144.185.144    free         normal   Ready   mil01    1.20.7_1543*

つまりこの時点で(上述の結果であれば)アプリケーションは http://169.51.204.190:30601/ で稼働している、ということになります。ウェブブラウザを使って、アプリケーションの URL(上述の方法で確認した URL)にアクセスしてみます:
scratch1


Scratch の編集画面が表示できました。各種ブロックを使って GUI プログラミングおよび動作確認ができます(共有機能は無効のようです):
scratch2



【YAML ファイルの解説】
YAML ファイルはこちらを使っています:
apiVersion: v1
kind: Service
metadata:
  name: scratch3
spec:
  selector:
    app: scratch3
  ports:
  - port: 8601
    protocol: TCP
    targetPort: 8601
    nodePort: 30601
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: scratch3
spec:
  replicas: 1
  selector:
    matchLabels:
      app: scratch3
  template:
    metadata:
      labels:
        app: scratch3
    spec:
      containers:
      - name: scratch3
        image: kadok0520/mit-scratch3
        ports:
        - containerPort: 8601

Deployment 1つと、Service 1つ、環境変数の指定も不要で本シリーズで紹介する 30 個の中でも指折りにシンプルな YAML ファイルです。一応解説を加えておきます。アプリケーションそのものは 8601 番ポートで動作するように作られているため、NodePort 30601 番を指定して、外部からは 30601 番ポートでアクセスできるようにしています(NodePort として指定可能な番号の範囲は 30000 ~ 32767 です、指定しない場合は空いている番号がランダムに割り振られます)。また ReplicaSet は1つだけで作りました。


デプロイしたコンテナイメージを削除する場合はデプロイ時に使った YAML ファイルを再度使って、以下のコマンドを実行します。不要であれば削除しておきましょう:
$ kubectl delete -f scratch3.yaml


【紹介したイメージ】
https://hub.docker.com/r/kadok0520/mit-scratch3


【紹介記録】
Dayカテゴリーデプロイ内容
0準備準備作業
1ウェブサーバーhostname
2Apache HTTP
3Nginx
4Tomcat
5Websphere Liberty
6データベースMySQL
7phpMyAdmin
8PostgreSQL
9pgAdmin4
10MongoDB
11Mongo-Express
12Redis
13RedisCommander
14ElasticSearch
15Kibana
16CouchDB
17CouchBase
18HATOYA
19プログラミングNode-RED
20Scratch
21Eclipse Orion
22Swagger Editor
23R Studio
24Jenkins
25アプリケーションFX
262048
27DOS Box
28VNC Server(Lubuntu)
29Drupal
30WordPress

MIT(マサチューセッツ工科大学)が開発した教育用プログラミング環境「スクラッチ」は、ウェブブラウザでこちらのサイトを訪れることで利用することができます。一般的にはこの方法で利用することが(後述の方法と比較して常に最新版が利用できる、といったメリットもあり)推奨されます:
2019112001


最新バージョン(2019/11/18 時点では 3)と比較しての互換性などはありませんが、バージョン 1.x ではメッセージングによる外部連携を行うことができました。このバージョンは、今でもダウンロードしてインストールすることで自分の環境から利用することができます:
https://scratch.mit.edu/scratch_1.4


2019年11月現在、普通にスクラッチを利用する場合の環境は上述2つのいずれかになると思っています。ただインターネット環境に制約があるケースなど、特殊な環境でも最新版を利用することができないわけではありません。今回はそのような特殊なケースを想定し、Kubernetes (以下 k8s)環境の中にインストールしたスクラッチを使う方法を紹介します。

なお、以下つらつらと記述していますが、そんなに特別なことを書いているつもりはなく、「ごく普通に k8s に MIT スクラッチのイメージをデプロイ」しているだけです。どちらかというと自分の備忘録としてのブログエントリです。


【準備】
まず k8s 環境を用意します。独自にインストールした k8s 環境でもいいし、minikube 環境でもいいし、クラウドベンダーのサービスを使うもアリです。自分の環境からの利用に支障がないものを使ってください。なお以下では IBM Cloud から提供されている IKS(IBM Kubernetes Services) を使った例を紹介しています。IKS の場合は kubectl コマンドに加え、ibmcloud コマンドの導入も必要になります。詳しくはこちらを参照ください:
https://github.com/dotnsf/iks-handson/tree/master/Lab0

また minikube 環境を Windows 10 + WSL 環境下で作る場合の手順は以前のブログエントリで紹介したことがあります。こちらの環境を使う場合は以下を参照ください:
Windows 10 に minikube を導入して WSL から利用する


以下の手順に進む前に ibmcloud コマンドを使った IBM Cloud へのログインや環境変数の設定などを済ませておくようにしてください。詳しくは上述のリンク先を参照ください。


【デプロイ】
MIT スクラッチの docker イメージを使って k8s 上にデプロイします。今回はこのイメージを使わせていただきました:
https://hub.docker.com/r/kadok0520/mit-scratch3

(↑ MIT スクラッチ version 3 の docker イメージのようです)


デプロイ手順は以下になります(以下では mit-scratch3 という名称でデプロイしています):
$ kubectl run mit-scratch3 --image=kadok0520/mit-scratch3

$ kubectl get pod (pod の状態を参照し、 READY が 1/1 になっていることを確認)

NAME                                READY   STATUS    RESTARTS   AGE
pod/mit-scratch3-795d945bcb-2mj2b   1/1     Running   0          16h



"kubectl get all" の結果、mit-scratch3 の pod が動いていることが確認できました。

このままだと外からの利用ができないため、ポートフォワーディングを使って公開します。イメージのドキュメントによると、このイメージは内部的には 8601 番ポートを使って動作するようなので、このポート番号を指定して expose した上で、service の状態を確認します:
$ kubectl expose depoyment mit-scratch3 --type="NodePort" --port=8601

$ kubectl get service mit-scratch3 (service の状態を参照し、 POST を確認)
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE mit-scratch3 NodePort 172.21.228.178 8601:32686/TCP 16h

"kubectl get service" の結果、mit-scratch3 は 32686 番ポートで外部公開されたことが確認できました。

また、このサービスのパブリック IP アドレスも確認します。パブリック IP アドレスの確認方法は使っている k8s 環境によって異なりますが、IBM Cloud の IKS の場合であれば次のコマンドで確認できます("mycluster" 部分は作成したクラスタの名称):
$ ibmcloud ks workers mycluster

OK
ID                                                     パブリック IP   プライベート IP   フレーバー   状態     状況     ゾーン   バージョン
kube-bn92ui5d00ng3ftqj7gg-mycluster-default-00000052   184.173.5.49    10.47.84.230      free         normal   Ready   hou02    1.14.8_1538

上記例であれば 184.173.5.49 がパブリック IP アドレスとなっていることが確認できました。つまりこの例であれば、ここまでの結果から http://184.173.5.49:32686/ にアクセスすることで k8s 環境内にデプロイされた MIT スクラッチにアクセスできる、ということになります。


【動作確認】
上記手順で確認した URL にウェブブラウザでアクセスして動作確認します:

2019111800


動いているようです。


【後作業】
作成した環境(pod, service, deployment)を削除するには以下のコマンドを実行します:
$ kubectl get all (mit-scratch3 の pod, service, deployment が存在していることを確認)

$ kubectl delete deployment mit-scratch3 (deployment を削除)

$ kubectl delete service mit-scratch3 (service を削除)

$ kubectl get all (mit-scratch3 の pod, service, deployment が削除されたことを確認)




たまに子供や初心者を相手にプログラミングを教えてみせたりする際に Scratch を使っています:
Screenshot from 2018-05-04 15-28-23


MIT メディアラボが開発した GUI によるプログラミング開発言語および実行環境です。プログラムをエディタでガリガリと記述するような、いわゆる「コーディング」に相当する作業があまり必要なく、GUI を中心とした見た目に対する処理や変更をイベント単位に足していきながら少しずつ動くものを作っていくものです。そのためユーザーが完成形をイメージしながら作っていくことができ、コーディングそのものに不慣れな人がプログラミングを理解するのに向いていると思っています。

この Scratch は良くも悪くも GUI 中心の作業になるため、他の環境との連携が難しい(というか、そもそもどういう外部インターフェースが用意されているのかわかっていなかった)という印象を持っていました。Scratch の閉じた世界の中では初心者にも簡単でわかりやすい、という面があるのと同時に、Scratch 以外の環境とは繋がりにくいと思っていました。

で、なんかインターフェースが公開されてないかなあ・・・ と思って探していたら、この Scratch の国内第一人者でもある石原さんが書かれた一連のブログを見つけました:
Scratch(スクラッチ)を外部のプログラムなどとつなぐ「遠隔センサー接続」を解説する(その1)


↑このブログで書かれている内容は Scratch 1.4 の「遠隔センサーを有効に設定」して 42001 番ポートを開放した上で、TCP/IP のメッセージングによる連携を Ruby で行う、というものです。基本的にはほぼ同じ内容を Node.js で実装してみようと思い、調べた結果をまとめました。


なお、石原さんは「まちくえすと」の開発などで活躍されていてご存知の方もいらっしゃると思いますが、拙作マンホールマップiOS アプリ版の開発に尽力いただいたご縁もあり、そのお付き合いの中で Scratch のことも教えていただきました。僕にとっては「Scratch の先生」でもあります。石原さん、このブログとても助かりました。ありがとうございます!



まず、以下の作業を行う前提として、Scratch はローカルインストール可能なバージョン 1.4 を使う必要があります。公式サイトからオンライン版であるバージョン 2.0 以降を利用することも可能ですが、以下で紹介する Node.js 連携は Scratch 1.4 をローカルインストールして使う想定で記載しています。各種 OS 向けの Scratch 1.4 はこちらからダウンロードして導入してください(以下、Ubuntu 16.04 環境に Scratch 1.4 を導入した前提で記述します):
https://scratch.mit.edu/scratch_1.4/



まず最初に、Scrach を外部連携するためのポート開放を行います。Scratch 1.4 を起動し、「調べる」カテゴリ内「●●センサーの値」と書かれたブロックを右クリックして、「遠隔センサー接続を有効にする」を選択します:
Screenshot from 2018-05-04 15-29-09


すると「遠隔センサー接続が有効になりました」という確認ダイアログが表示されます:
Screenshot from 2018-05-04 15-29-39



この作業後、Scratch は 42001 番ポートで接続できるようになっています。つまり僕の以前のブログで紹介したような TCP/IP プログラミングによって Scratch との TCP/IP 接続が可能になっているのでした。試しに以下のような Node.js プログラム(scratch01.js)を書いて実行してみます(以前のブログで書いたものよりも更に簡略化し、最小限必要な内容だけにしています):
var net = require( 'net' );

//. 接続先 IP アドレスとポート番号
var host = '127.0.0.1';
var port = 42001;

//. 接続
var client = new net.Socket();
client.connect( port, host, function(){
  console.log( '接続: ' + host + ':' + port );
});

//. サーバーからメッセージを受信したら、その内容を表示する
client.on( 'data', function( data ){
  console.log( '' + data );
});

↑このプログラムを実行すると、127.0.0.1(自分自身)の 42001 番ポートに TCP/IP 接続し、接続先から何かメッセージが送られてくるとそのメッセージ内容を文字列化してそのまま表示する、というものです。これをまず node コマンドを使って実行しておきます:
$ node scratch01.js

これで 42001 番ポートに接続し、メッセージの受信待ち状態になりました。


そして Scratch 側からはこの(42001 番ポートの)接続先に対してメッセージを送信してみます。この処理を行うには「制御」カテゴリ内「●●を送る」ブロックを使います:
Screenshot from 2018-05-04 15-40-55


同ブロックを右クリックして「新規」を選択し、メッセージの名前を任意に指定します。以下の例ではメッセージの名前に Hello と指定してます:
Screenshot from 2018-05-04 15-42-14


するとブロックの表示内容が「Hello を送る」と切り替わります。この状態で同ブロックを何度かマウスでクリックします(クリックするたびにこのブロックが処理を実行します):
Screenshot from 2018-05-04 15-42-41


すると先に実行していた Node.js プログラムのコンソール画面に(最初の制御文字に続いて) 
broadcast "Hello"
という文字行がクリックするたびに表示されます:
Screenshot from 2018-05-04 15-46-59


この結果から Scratch の「●●を送る」ブロックを1回実行すると
broadcast "(指定したメッセージ)"

という文字列が送信される、ということが分かりました。これで Scratch から Node.js のプログラムにメッセージを送信し、Node.js プログラム側でその内容を受信することができました。


この応用で逆に Node.js から Scratch にメッセージを送ることもできます。例えば scratch02.js を以下の内容で作成します(接続後に 'broadcast "a"' というメッセージを Scratch に送信する、という内容です):
//. scratch02.js
var net = require( 'net' );
var host = '127.0.0.1';
var port = 42001;

var client = new net.Socket();
client.connect( port, host, function(){
  console.log( '接続: ' + host + ':' + port );

  var msg = 'broadcast "a"';
  var len = msg.length;
  var buf = pack( len );
  client.write( buf + msg );  //. msg の内容を Scratch へ送信
});

//. 4バイトのバイト列(Buffer)に変換
function pack( n ){
  var m1 = n % 256;
  n = Math.floor( n / 256 );
  var m2 = n % 256;
  n = Math.floor( n / 256 );
  var m3 = n % 256;
  var m4 = Math.floor( n / 256 );

  return new Buffer( [ m4, m3, m2, m1 ] );
}



そして Scratch 側では 'broadcast "a"' というメッセージを受け取ったら何らかの処理がスタートする、というプログラムを書いておきます(下の例ではスプライト1の猫のキャラクターが画面内を歩き始める処理がスタートする、という内容にしています):
Screenshot from 2018-05-05 15-54-06


この状態で scratch02.js を実行すると、TCP/IP 通信によって Scratch に接続し、broadcast "a" というメッセージが送られ、Scratch のスプライト1のキャラクターが壁に跳ね返りながら動き回る処理がスタートします(特に止める方法を用意していないので、止めるには画面右上の赤丸部分をクリックしてください):
Screenshot from 2018-05-05 16-02-12


これで Scratch から Nodejs にメッセージを送ったり、逆に Node.js から Scratch にメッセージを送る、ということが実現できました。

 

このページのトップヘ