AWSのEC2(WindowsServer)でキャプチャ取得を自動化したかった話

主題のままなのですが、AWSのEC2でテストを消化する機会があり、ファイル収集やキャプチャ取得が面倒だと思ったので、パワーシェルで自動化しました。

キャプチャ取得は、メモ帳とエクスプローラー。
ファイル収集はそんなに難しくないと思うので省略です。

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

$exeFolder = $MyInvocation.MyCommand.Path
$exeFolder = Split-Path "$exeFolder" -Parent

Function openExprolerAndGetCapture($folderPath) {

    # エクスプローラーを開く
    Start-Process explorer.exe -ArgumentList $folderPath -WindowStyle Maximized
    # ウィンドウが表示されるのを待つ
    Start-Sleep -Seconds 5

    # エクスプローラーのウィンドウを探す
    $folderName = $folderPath.split("\")
    #Write-Host $folderName[-1]
    $explorerWindow = Get-Process | Where-Object { $_.MainWindowTitle -eq $folderName[-1] }

    if ($explorerWindow) {

        # 画面キャプチャを取得
        $rect = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds
        $bitmap = New-Object System.Drawing.Bitmap($rect.Width, $rect.Height)

        $graphics = [System.Drawing.Graphics]::FromImage($bitmap)
        $zero = New-Object System.Drawing.Point(0, 0)
        $graphics.CopyFromScreen($zero, $zero, $bitmap.Size)

        # 画像を保存
        $saveFileName = $exeFolder + "\" + $folderPath.replace("\", "_").replace(":", "") + ".png"
        Write-Host $saveFileName
        $savePath = $saveFileName
        $bitmap.Save($savePath, [System.Drawing.Imaging.ImageFormat]::Png)

        # ウィンドウを閉じる
        $explorerWindow.CloseMainWindow()

    }
    else {
        Write-Host "エクスプローラーのウィンドウが見つかりませんでした。"
    }

}

Function openNotepadAndGetCapture($filePath) {

    # メモ帳を開く
    Start-Process C:\Windows\notepad.exe -ArgumentList $filePath -WindowStyle Maximized
    # ウィンドウが表示されるのを待つ
    Start-Sleep -Seconds 5

    # メモ帳のウィンドウを探す
    $fileName = $filePath.split("\")
    $windowTitle = $fileName[-1] + " - メモ帳"
    Write-Host $windowTitle
    $explorerWindow = Get-Process | Where-Object { $_.MainWindowTitle -eq $windowTitle }

    if ($explorerWindow) {

        # 画面キャプチャを取得
        $rect = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds
        Write-Host $rect.Width ":" $rect.Height
        $bitmap = New-Object System.Drawing.Bitmap($rect.Width, $rect.Height)

        $graphics = [System.Drawing.Graphics]::FromImage($bitmap)
        $zero = New-Object System.Drawing.Point(0, 0)
        $graphics.CopyFromScreen($zero, $zero, $bitmap.Size)

        # 画像を保存
        $saveFileName = $exeFolder + "\" + $filePath.replace("\", "_").replace(":", "").replace(".", "_") + ".png"
        Write-Host $saveFileName
        $savePath = $saveFileName
        $bitmap.Save($savePath, [System.Drawing.Imaging.ImageFormat]::Png)

        # ウィンドウを閉じる
        $explorerWindow.CloseMainWindow()

    }
    else {
        Write-Host "メモ帳のウィンドウが見つかりませんでした。"
    }

}

try {

    # memo
    openNotepadAndGetCapture -filePath "C:\test\test.txt"

    # explorer
    openExprolerAndGetCapture -folderPath "C:\test"

}
finally {
}

さくらVPSでmariaDB + nginxをDockerで

なぜDockerなのか

試行錯誤したいからです。

構成

OS:Ubuntu 20.04
スクリプト:Setup and update
 ー初回起動時にパッケージ更新する:する
 ー日本語環境 ja_JP.UTF-8 に変更する:する

準備

アップデートなどしていきます。

sudo apt update
sudo apt upgrade

Docker

sudo apt docker.io

Docker-compose

sudo apt docker-compose

docker-compose.yml

太字部分は適宜、変更してください。
特にmariaDBは、ポート番号を変更してください。
バージョンを固定する必要ないならlatestとかでも大丈夫じゃないでしょうか。(試してない)
できればstable(安定版)にすることをおすすめします。

version: '3'

services:
  db:
    image: mariadb:11.0.2
    environment:
      MYSQL_ROOT_PASSWORD: Password
    ports:
      - '3306:3306'
    command: --default-authentication-plugin=mysql_native_password
    volumes:
      - ./mysql/data:/var/lib/mysql
  web:
    image: nginx:1.24.0
    volumes:
      - ./nginx/templates:/etc/nginx/templates
    ports:
      - "8080:80"
    environment:
      - NGINX_HOST=www.domain.net
      - NGINX_PORT=80

アクセス

パケットフィルタリングを有効にしている場合は通すようにしましょう。
mariaDBのユーザIDとパスワードは、上記のymlの設定ならroot/Passwordです。

当然ながら、外部からアクセスする場合にはドメインが必要になります。
(もしくはIPアドレス指定ですかね)

まとめ

とりあえず、アクセスできることだけ確認しました。
アプリの実装やデプロイ自動化などについては、また今度。

アプリ開発のサーバーサイド、いったん保留か。

■検討

 まず、制約事項としてさくらVPSの最小プランを選択しました。
 なので、その環境で動作する必要がありますので、軽量であることが条件となります。
 実際に何度もOSの再インストールをして試してみましたが、そもそも各種ライブラリなどがきちんとインストールできないとかありましてね。。。
 とりあえず、脆弱性の面でPHPなどは避けておきたいので、自分の中ではRubyかPythonかなと見当をつけていました。

■Ruby On Rails

 何度もOS再インストールを繰り返しながら何とかインストールができそう!ってところまで行きましたが、結局はメモリが足りずに断念しました。

 結構時間もかかっていたのに残念です。
 潤沢に資金があればプランをスケールアップして採用するのもアリでしたね。

■Python

 Rubyの次点として考えておりましたが、Rubyがダメそうとなって本格的に検討しました。
 Pythonで軽量なWEBアプリケーションが作成できるのかなと思っていましたが、FastAPIというものがあるらしく、それを使おうと思います。
 さくらVPSにはPython向けセットアップスクリプトがあったんですけど、全然インストールされてないんですよね。。。
 サーバーサイドは諦めて、アプリにデータを含めてリリースする方が早くリリースできそうなんですよねー。

HTTPステータスに502を返却している

主題のとおり、HTTPステータスに502を返却していたので、原因を調査して対策した話。

【原因調査】

まずはネットで502ってどんな時に出てくるの?ってのを調べました。
色々見て回ったところ「負荷がかかっている」みたいなのを見て、確かに日中帯に出現していて夜間帯は全然出ていない、というところで納得しました。

が、
実は負荷ではなく、別な原因がありました。

【原因判明】

原因はTomcatのコネクションプールサイズの最大数と最小数が異なるためです。
Tomcatのコネクションプールは、使用していないコネクションを自動で開放(切断)します。
なので、使用していないコネクションを開放するタイミングでリクエストが来た時はそのまま開放しちゃうので502が発生してしまうということみたいですね。

ちなみに同様の事象なのかはApacheのエラーログを見れば分かると思います。
下記のようなエラーが出ていると思うので。

proxy: error reading status line from remote server...


ちょっと気になったのは、色々サイトを見て回ったけど、何故か「Apacheにコネクションプールを使用しない設定にしましょう」(proxy-initial-not-pooledの有効化)って対策が出てくるんですよね。

【対策】

便利な機能をOFFにしましょうというのは納得できなかったのでもっと調査した結果、コネクションプールの最大数と最小数を同数にしました。

原因が不要なコネクションを閉じてしまうというなら、常にコネクションを一定量に保つようにしておきましょうということですね。

自力で思いついた訳ではないんですけど、ここに書いた方が記憶に残りそうだし、同じことでつまずいている人がいた場合に他の対策方法を提示できるかもしれないので。(^^)

※バックエンド側に設定する方法があると思いますが、それはバージョンやフレームワークとかミドルウェアで変わってくると思うので記載はしません。

Python練習問題

Chainer Tutorialに記載されている練習問題をやってみたので、結果をメモとして残しておきます。

問2.8 (制御構文)

2以上の整数 p が素数であるとは、「どんな 2 以上 p-1 以下の整数 k に対しても p は k で割り切れない」が成り立つことを指します。素数を小さい順から列挙すると、2357111317, … となります。 チュートリアルで学んだ制御構文である if や for を用いて、2 から 100 からまでに含まれる素数を列挙して下さい。

◆回答

a = [2]
for x in list(range(3, 101)):
    if all([x % y > 0 for y in list(range(2, x))]):
        a.append(x)
print(a)

◆実行結果

[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

「rails new sample_app -G」が失敗

Ruby on railsの環境を作ろうとProgateのサイトを見ながら進めてたら、
下のような感じで失敗しました。

rails aborted!
Errno::ENOENT: No such file or directory - bs_fetch:open_current_file:open
bin/rails:4:in `<main>'
(See full trace by running task with --trace)
       rails  turbo:install stimulus:install
rails aborted!
Errno::ENOENT: No such file or directory - bs_fetch:open_current_file:open
bin/rails:4:in `<main>'
(See full trace by running task with --trace)

とりあえず–traceで詳細が見れるのかな?と思ったので次のコマンドを実行。

rails new sample_app --trace
C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/railties-7.0.3.1/lib/rails/generators/rails/app/app_generator.rb:258:in ``': No such file or directory - git config init.defaultbranch (Errno::ENOENT)

なんだか「Gitが入っていないから?」と思ったのでいったんGitをインストール。
しかし、再実行しても同様の失敗。

とりあえずrailsプロジェクトを作成しているのがデスクトップだったのが気になっていたで、
「C:¥work¥ruby」を作ってそこで再実行。

なんかうまくいきました。
パスか「C:\Users\xxxxx\OneDrive\デスクトップ\ruby_lesson」だったから、
階層か日本語が原因かな・・・?

複雑な条件分岐を分かりやすく

MapやSetを使う

複数のステータスのいずれかに一致するか、という条件判定をひとつずつ実装するのは非効率だし、分かりやすさや見易さを犠牲にすると思います。
MapやSetに存在するかを判定することで見やすく、分かりやすくなるのではないかと。

例)

public class Test {

	private static final Set<String> GOODS_SET;
	static {
		HashSet<String> map = new HashSet<String>();
		map.add("りんご");
		map.add("ぶどう");
		map.add("なし");
		map.add("もも");
		map.add("みかん");
		GOODS_SET = Collections.unmodifiableSet(map);
	}

	public static void main(String[] args) {

		if (GOODS_SET.contains("りんご")) {
			System.out.println("商品に存在します。");
		} else {
			System.out.println("商品に存在しません。");
		}

	}

}

条件分岐の名前で判定するので、分かりやすいと思います。
1点だけ難点を挙げるなら、テストで条件を網羅できたかが確認できないので、条件に含めているものが正しいのかをレビューできちんと確認する必要があるところです。

本番環境と検証環境を区別させたい

目的・意図

検証環境を利用していて、誤って本番環境にアクセスしてしまわないかは心配ですよね。
誤って本番環境にアクセスしてゴミデータを登録したりとか、ありそうですよね。

提案

Chromeの設定でサイトごとに画像を表示させない設定ができるので、その設定を試してみてはいかがでしょうか?

右上の3点リーダーから「設定」
→左のメニューから「プライバシーとセキュリティ」
→「サイトの設定」
→「画像」
→「画像の表示を許可しないサイト」に対象のURLを追加。

最近では、画像を全く使っていないというようなサイトは少ないと思いますので、
「画像が表示されない→本番環境だ」となるのではないでしょうか。

昔、担当したことのあるシステムでは検証環境だけ背景色が変わっていたりしていましたが、
これならコードをいじらなくて良いので、お手軽かなと思います。