WindowsにDocker環境作る(DockerDesktop)

事前知識

VMWare時代の人間なので、まずは改めて外編をおさらい。

VMWareとかVirtualBoxなどの仮想化はゲストOSを立ち上げているため環境を選ばないが重く、DockerはOSはLinux縛りだがローカルに依存し、その上でコンテナ単位で動かすので扱いやすく高速。

じゃあアプリ開発する場合なら全部Dockerでいいんじゃないですか、という感じですが、上位互換というわけではなく環境をまるごと作る仮想サーバとコンテナではそれぞれ特徴があるので、ちゃんと理解しながら運用しようねと。
参考。
blog.inductor.me


それからここ10年くらいの、Vagurantも絡めたトレンド変遷。
これについてはこちらの記事がとても分かりやすい。
gomokulog.gomocool.net

ずっと開発してきている人なら当然のように知っている流れでしょうが、しばらくこういう開発現場から離れていたのでね。こういう理解はとても大事。

そういえば数年前、WindowsにDocker入れるためにWSL2の設定しようとして、その時初めて、ネットで購入した中古PCが「Pro」じゃなく「Home」だった事に気付いて絶望したなぁ。(Win10のHomeはWSL2無いです)
もちろん発送側のミスだけど、受け取ってしばらく経ってたから交換してもらえなかった…。

環境

エディション Windows 11 Pro
バージョン 22H2

インストール(再起動2回)

WindowsにWSL2をインストール

管理者権限でPowerShellを開き、以下を実行。

wsl --install

再起動せよと表示されますので、PCを再起動。

Ubuntuのユーザー登録

PCが立ち上がると勝手にUbuntuも起動してくれている。だいぶ親切になったようです。
このUbuntuが、WSL2を動かすディストリビューション(Linux)にあたるのだと思います。

要求通り、適当にユーザー名とパスワードを入力。

起動してこなかった場合は、アプリの一覧から「Ubuntu」とか「WSL」とか探して起動すればよさそうです。

Docker for Windowsをダウンロード

こちらから。
https://docs.docker.com/desktop/install/windows-install/

インストール

「Docker Desktop Installer.exe」がDLされますので、素直に設定してインストール。

再起動

これを押すとPC再起動しますので注意。(油断してた)

使用許諾

Docker Desktop を起動するとコレが出てきます。
なにやら金額が書いてありますが、個人利用なら無料なのでそのままAcceptしてよさそうです。

起動しました

Updateがあるのでバージョンアップし、アカウントも以前作成したのでログイン。

カレントの場所

さて、だいたいこの後の作業で「カレントディレクトリで…」みたいなことになるのですが、いったいこの場合のカレントはどこなのか。
Explorer上のアドレスはここです。

\\wsl.localhost\Ubuntu\home\%username%

エクスプローラでは以下の様に見えているはずなので、Ubuntuフォルダから素直に掘っていってもよさそうです。

また、Dockerを触るターミナルは色々なパターンがありそう。

  • Windowsメニューから「Ubuntu」を選択(上記で作成したユーザーのログイン状態でターミナルが起動)
  • Windowsメニューから「WSL」を選択(上記と同様、ログイン状態でターミナルが起動)
  • PowerShellを管理者権限で実行し、「wsl」と打つ(Ubuntuにログインできる。ただしカレントディレクトリが、Ubuntuから見たWindowsディレクトリという謎な状態になる)
イメージとコンテナの場所

ちなみに、コンテナとイメージはそれぞれ以下に配置されるようです。
基本的な操作ではアクセスすることはおそらく無い。

# イメージやコンテナ
%LocalAppData%\Docker\wsl\data\ext4.vhdx

# エンジン
%LocalAppData%\Docker\wsl\distro\ext4.vhdx

EC2でApacheが起動しない(already running)

EC2にて、初めてApacheを起動しようとしたらエラー。
suEXECが原因だったっぽい。

環境

Amazon Linux 2023 AMI
Server version: Apache/2.4.56 (Amazon Linux)

エラー

[ec2-user@aws-test  ~]$ sudo service httpd start
Redirecting to /bin/systemctl start httpd.service
Job for httpd.service failed because the service did not take the steps required by its unit configuration.
See "systemctl status httpd.service" and "journalctl -xeu httpd.service" for details.
[ec2-user@aws-test ~]$ systemctl status httpd.service
× httpd.service - The Apache HTTP Server
     Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; preset: disabled)
    Drop-In: /usr/lib/systemd/system/httpd.service.d
             └─php-fpm.conf
     Active: failed (Result: protocol) since Thu 2023-10-10 20:50:10 JST; 43s ago
       Docs: man:httpd.service(8)
    Process: 2743 ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND (code=exited, status=0/SUCCESS)
   Main PID: 2743 (code=exited, status=0/SUCCESS)
     Status: "Reading configuration..."
        CPU: 37ms

Oct 10 20:51:14 aws-test systemd[1]: Starting httpd.service - The Apache HTTP Server...
Oct 10 20:51:14 aws-test httpd[2743]: httpd (pid 2469) already running
Oct 10 20:51:14 aws-test systemd[1]: httpd.service: Failed with result 'protocol'.
Oct 10 20:51:14 aws-test systemd[1]: Failed to start httpd.service - The Apache HTTP Server.

プロセスを消す

apacheが再起動できなくなった
linux - systemctl restart httpd Failed to start The Apache HTTP Server httpd pid already running - Stack Overflow

こちらなどをみると、既存プロセスが専有中(already running)だから、PIDを削除すればよさそう。
しかし、そんなプロセスは上がっていないので違うと思われる。そもそも一回も起動してない。

ついでにec2-userでログインしているからなのか、httpd.pidファイルをfindしても権限外でヒットしない。

ログを確認

[ec2-user@aws-test ~]$ sudo less /var/log/httpd/error_log
[Thu Oct 10 20:50:47.339081 2023] [suexec:notice] [pid 2449:tid 2449] AH01232: suEXEC mechanism enabled (wrapper: /usr/sbin/suexec)
[Thu Oct 10 20:50:47.371717 2023] [lbmethod_heartbeat:notice] [pid 2469:tid 2469] AH02282: No slotmem from mod_heartmonitor
[Thu Oct 10 20:50:47.372703 2023] [systemd:notice] [pid 2469:tid 2469] SELinux policy enabled; httpd running as context unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[Thu Oct 10 20:50:47.377719 2023] [mpm_event:notice] [pid 2469:tid 2469] AH00489: Apache/2.4.56 (Amazon Linux) configured -- resuming normal operations

suEXECを無効化してみる

suEXECを無効化するにはファイルを削除してよいということなので、削除。

[ec2-user@aws-test ~]$ ls -la /usr/sbin/suexec
-r-x--x---. 1 root apache 24296 Mar 17  2023 /usr/sbin/suexec
[ec2-user@aws-test ~]$ sudo mv /usr/sbin/suexec /usr/sbin/suexecbkup
[ec2-user@aws-test ~]$ ls /usr/sbin/suexec /usr/sbin/suexecbkup
ls: cannot access '/usr/sbin/suexec': No such file or directory
/usr/sbin/suexecbackup

リブートしたら無事、立ち上がりました。

2行目のNo slotmen from mod_heartmonitorもオフってよいものらしいが、ひとまず起動したので今回は放置。

参考

助かりました。
qiita.com

kintoneの計算式でドロップダウンの値を使う

数分間ハマったので一応メモ。

計算したい場合は数字に変換が必要

選択入力でラジオボタンやドロップダウンから選択させる場合、値は文字列。
数式に文字列が入ってると「#VALUE!」表示になるので、数値変換が必要。
変換関数はないので、IF文で分岐させる。

チャレンジ!きんとん関数ドリル(解説つき)〜kintone Café JAPAN2021|松田正太郎@プロジェクト・アスノート|note

計算フィールドを一枚噛ませると数値変換してくれるんだけど、数が多いとクソになるので、素直にIF文でやりました。
選択肢が増えるとIF文の分岐も増えるので、選択肢が多い場合は考えものだな…。
そうなるとjsハメたほうが速いんじゃないかな。

ドットを含むダブルクォーテーションに囲まれた文字列の有無を検索

久々に正規表現が分からなくて泣きそう。
「ドットを含む、ダブルクォーテーションに囲まれた文字列」の抽出はできなかったのですが、有無の確認まではできたのでメモっておきます。

やりたいこと

データはjson風。実態はText(←重要!)。

{
    "group":"apple",
    "data":{
        "page":1,
        "Name":"hoge.hoge",
        "value":12.33
    }
},
{
    "group":"banana",
    "data":{
        "page":1,
        "Name":"fugafuga",
        "value":85.0
    }
}

こういう感じ。
実際にはtextデータのため、このデータが改行無くズラッと一行に並んだものが対象です。

このデータの中の、「hoge.hoge」のように、NameがKeyのvalueの中にドットを含むところだけをヒットさせたい。

ややこしいところ

  • ダブルクォーテーションが大量にあるので、「.*?」等を使うと意図しない量の文字列がヒットしてしまう
  • 他のValueには正しいドットがあるからヒットさせたくない
  • 前後の文字列が繰り返し有りのため特定し辛い

つらい。

結局、やったこと

こちらのサイトさんに助けていただきました。
[正規表現] .*?は最短マッチではない - Qiita

"Name":"[^""]*\.

//もしくは

"Name":"[^""]*[.]

こちらで何とか対処。
最後の「\.」でヒットしたドットで検索が終わるので、上記のデータで言えば「12.」までしかヒットしません。
なので「12.33」を引っ張ることは結局できなかったのですが、今回は「ドットを含むValueが一つでもあるかどうか」を検索させたかったため、一応目的は達成しました。

余談

今回、「1つもヒットしなかったらTrue」というスクリプトを組みたかったのですが、これもまた難しかった。

結局スクリプト側で「not.match」させるという方法となり、コードの可読性的にもそちらのほうが正しい気もするのですが、「ドットを含まない・NameのValue・しかヒットしない」という正規表現も書きたかった。
(寝ぼけてるので自信がないですが発想自体はありえなくないですよね)

いつか分かったら追記します。


GASでスタンドアロンスクリプトを作成して複数のスプレッドシートから利用する

スプレッドシートに埋め込む形のコンテナバインドスクリプトではなく、複数のスプレッドシートから呼び出したくなったので。

こちらの記事、まるっとそのままですが備忘で書いておきます。
teratail.com

MyDriveから新規作成

スタンドアロンは「マイドライブ」の「新規」>「その他」>「Google Apps Script」から作成。

f:id:hiro-29:20220405165755p:plain

スクリプトの保存

「コード.js」の中にスクリプト本体を書いて、「無題のプロジェクト」のところを変更します。(これが日本語だと呼び出し時に上手くいかないらしい?)
f:id:hiro-29:20220405174623p:plain

もちろんスクリプトは「保存」します。
※これ忘れると、意外とキャッシュが残っている感じになって上手くいかなかったりする。
※余談ですが最近のアプリの「離脱したら勝手に保存してくれる」機能のせいか変更を明示的に保存しないことで困ったことが何度かある…よくない。

デプロイ

この時点ですでに連携用の「スクリプトID」が発行されているようなので、おそらくこのままでも権限周りが問題なければ連携できると思われます。
今回はちょくちょく修正がかかる予定なのでデプロイします。(動作確認してませんが、これしないと保存した瞬間に変更が反映されてしまうのだと思われる)

右上の「デプロイ」>「新しいデプロイ」
f:id:hiro-29:20220405170759p:plain

種類を「ウェブアプリ」で選択し、権限周りを設定して「デプロイ」
f:id:hiro-29:20220405172120p:plain

スクリプトIDをコピーする

左カラムの「プロジェクトの設定」>「スクリプトID」をコピーしておく。
f:id:hiro-29:20220405173752p:plain

呼び出し側でスクリプトIDを連携

使いたいスプレッドシートを開いて「拡張機能」>「Apps Script」。
f:id:hiro-29:20220405172255p:plain

左カラムの「ライブラリ」の「+」から新規追加します。
さきほどの「スクリプトID」を入力>「検索」すると、以下のように表示されます。
一番下の「ID」に、ここでさきほど上記で入力したプロジェクト名が表示されればおそらくOK。
f:id:hiro-29:20220405174121p:plain
(自分はここで「保存」忘れで何度も「「appsscript.json」のエラー: サービス ID は空にできません」のエラーで「ID」にプロジェクト名が表示されないという事態に陥ってました…。保存しようね。)

呼び出し側のコンテナバインドスクリプトを作る

コードはこれだけでOK。
さきほど英数字で保存した「プロジェクト名.メソッド();」でコールできます。

function myfunction() {
  StandaloneScript.MainMethod();
}

自分はもともとコンテナバインドで作成したスクリプトスタンドアロン化したのですが、getActiveSheet などのローカルでしか正しく動かなさそうなメソッドもそのまま使えました。ラッキー。


本家ガイドはこちら。
developers.google.com

GASでopenByUrlする前に存在有無を確認する

OpenByUrlで指定した外部のスプレッドシートを開く場合、いきなり呼ぶとURLが壊れていたときに分かりにくい例外が返ってきてしまうので、それに対処します。

これ、頻出だと思うのですが全然ネットに類似記事がない。
検索キーワードが悪いのでしょうか…凹むな…。

openByUrlに投げる

シンプルに呼び方はこう。

//対象ファイルを開く
let DataFile = SpreadsheetApp.openByUrl("ここにファイルURL");

URLが間違っていたり、つまり「そんなファイル無いよ」というときに投げられるのが以下の例外。

Unexpected error while getting the method or property openByUrl on object SpreadsheetApp.

f:id:hiro-29:20220330223907p:plain

さらにスプレッドシートでこのメソッドを呼んでいるのですが、この例外のときに出てくるメッセージボックスがこれ↓。

SpreadsheetAppオブジェクトでのopenByUrlメソッドまたはプロパティの取得中に予期しないエラーが発生しました。

ご丁寧に自動翻訳してくれるのですが、それでもこれは非エンジニアが見たら
訳わかんないのでエラーを出す前に状態を確認します。

httpステータスコードで存在確認しちゃう

他にやり方が思いつきませんでした。。邪道なのかなぁ。
(URLで存在確認できるメソッドなんて無い…よね?)

//ステータスコードを確認
if(getStatusCode("ここにファイルURL") != 200) throw new Error("URL間違ってるよ");

function getStatusCode(url) {
  const response = UrlFetchApp.fetch(url, {muteHttpExceptions: true})
  return response.getResponseCode()
}

こちら↓ コピペさせていただきました。
httpをこうやって処理できるの知らなかった。ありがたい。
iwb.jp


リファレンスはここ。
URL Fetch Service
developers.google.com

フォルダレベルでファイルの存在チェックしたら?

存在チェックと言う意味では、フォルダとその中身のファイルをWhileして「その名前のファイルある?」とやるのがもしかしたら正しいのかも。
ただ今回はアカウントやフォルダを無関係に、一発で指定させたかったのでちょっとな。

特定のフォルダ内で順次ファイル処理とかであればそうであるべきかも。

例外をキャッチしてメッセージ書き換えればいいじゃん

最初これやろうとしたんですが、エラーコードが返ってくるわけじゃないので他の例外との切り分けができなかったんです。
e.errorcode とかいうプロパティがあればいいんですが‥。

e.messageの文字列比較などを無理やりやればできるのかもしれませんが、気持ち悪かったのであんまりトライしてないです。

画面動画キャプチャで、いちばんかんたんな字幕動画を制作(Wondershare Filmora+Windows ビデオエディター)

急ぎで画面を録画して字幕をつける必要があり、とにかく簡単な方法を探しました。
昔はフリーソフトを駆使して動画製作環境を整えたりしたもんだけど、今はそんなことやってる場合ではない。(@Windows

Wondershare Filmora をダウンロードしてインストール

無料で使えて、動画に透かしが入らない。
有料版プランもそこそこ良さそうだけど、今回は無料プランで使います。

filmora.wondershare.jp


動画を撮る

「画面録画」を押す。

f:id:hiro-29:20220314201059p:plain

スクリーンレコーダーが出現するので設定する。
gifレベルの動画でいいので、フレームレートは最低、画質は「良い」、それとマウスクリック表示はあり。
停止のホットキー忘れるとすごく止めにくいので、これは覚えておきます。

f:id:hiro-29:20220314203837p:plain

ちなみにこの画面は殆ど使わない。
スクリーンレコーダーを落としてしまった場合はここから。

f:id:hiro-29:20220314204355p:plain

ビデオエディター

「新しいビデオプロジェクト」をクリックしてプロジェクトを作成。

f:id:hiro-29:20220314224012p:plain

左上の「+追加」から録画した.mp4などを読み込んでストーリーボードへドラッグ&ドロップ。

f:id:hiro-29:20220314224414p:plain

字幕の付け方

このまま「テキスト」というところをクリック

f:id:hiro-29:20220314225208p:plain

右上に文字を追加すれば文字が追加できます。

f:id:hiro-29:20220314224813p:plain

しかしこのビデオエディターは、1シーンに1字幕しか設定できないため、キャプチャのようにストーリーボードに1ブロックしかないと字幕が1行しか出せません。

よって、動画を字幕を出したいところで分割します。

f:id:hiro-29:20220314225310p:plain


そうするとブロックが2つになるので、それぞれに字幕が設定できます。

f:id:hiro-29:20220314225539p:plain


ということは、1本の動画に10行の字幕を入れたい場合、10回近く「分割」しないといけないわけですね…。

仕上げは当然「ビデオの完了」です。


それから、たまにフリーズしますがプロジェクトデータは自動保存されているので、固まったと思った瞬間に落として再起動して大丈夫のようです。