DockerでSQL Serverのデータベースをリストアして起動する
はじめに
これまでSQL Serverを利用した開発は、EC2インスタンスを使用していました。
Dockerを使うと手元の環境で SQL Server を起動して開発を行う事が出来るので
今回はDockerの利点である環境の自動構築を行い、接続までの手順をまとめます。
開発環境
・Widnows10 Pro
・Docker Engine Community Version 20.10.5
使用するファイル
C:\DOCKER\SAMPLE-MSSQL │ docker-compose.yml │ ├─ mssql │ db-init.sh │ ddl.sql │ Dockerfile │ entrypoint.sh │ ├─ mssql-backup │ sampledb.bak │ └─ mssql-data
docker-compose.yml
version: '3' services: db: build: context: ./mssql/ dockerfile: ./Dockerfile container_name: sample-mssql-2017 ports: - "1433:1433" environment: - ACCEPT_EULA=Y - SA_PASSWORD=Sa@mple@dm1n - MSSQL_PID=Express - MSSQL_LCID=1041 - MSSQL_COLLATION=Japanese_CI_AS - PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" volumes: - ./mssql-data:/var/opt/mssql - ./mssql-backup:/var/opt/mssql/data/backup
Dockerfile
FROM mcr.microsoft.com/mssql/server:2017-latest COPY ./entrypoint.sh /usr/src/entrypoint.sh COPY ./db-init.sh /usr/src/db-init.sh COPY ./ddl.sql /usr/src/ddl.sql WORKDIR /usr/src/ RUN chmod +x /usr/src/db-init.sh CMD /bin/bash ./entrypoint.sh
entrypoint.sh
デバッグし易いように db-init.sh の実行ログを log.txt として残しています。
./db-init.sh >> /var/opt/mssql/data/backup/log.txt 2>&1 & /opt/mssql/bin/sqlservr
db-init.sh
25s の待ち時間はリストアを行う為にSQL Serverが起動するまで待ちます。
10s の待ち時間はデータベースユーザを追加する為にリストアの終了を待ちます。
/bin/sleep 25s touch /var/opt/mssql/data/sampledb.mdf touch /var/opt/mssql/data/sampledb_Log.ldf /opt/mssql-tools/bin/sqlcmd -H localhost -U sa -P S@mple@dm1n -Q "RESTORE DATABASE sampledb FROM DISK = '/var/opt/mssql/data/backup/sampledb.bak' WITH FILE = 1, STATS = 5, REPLACE, MOVE 'sampledb' TO '/var/opt/mssql/data/sampledb.mdf', MOVE 'sampledb_Log' TO '/var/opt/mssql/data/sampledb_Log.ldf'" /bin/sleep 10s /opt/mssql-tools/bin/sqlcmd -H localhost -U sa -P S@mple@dm1n -i /usr/src/ddl.sql
ddl.sql
EXECUTE AS LOGIN = 'sa' USE sampletable GO DROP USER SampleUser CREATE USER SampleUser for login SampleUser ALTER USER SampleUser WITH DEFAULT_SCHEMA = dbo GO GRANT CONNECT TO SampleUser GO exec sp_addrolemember 'db_owner', SampleUser GO
SQL Server の起動
docker compose up --build
SQL Server の接続
SQL Server Management Studio を使用して接続ができることを確認しました。
参考資料
macでSQL Server on Linuxコンテナに自動でサンプルDBを取り込む手順 – お役立ち情報サイト・アレアレ
Docker + MySQLで開発環境用DBの作成 - もぐもぐプログラミング
Dockerfileを書き換えても反映されないときはbuild忘れ | へっぽこ開発室
[Windows] Dockerを使用してホスト環境を汚さずにmssql-server-linuxを使う | LaptrinhX
sleep: command not found - Query Admin
SQL Server on Linux for Docker でのエラー対策 - 蒼の王座・裏口
sql server - Restore database in docker container - Stack Overflow
Create Login, User, assign Permission: SQL Server Tutorial
sql server - TSQL to Map User to Database - Stack Overflow
C#から踏み台サーバを経由してSQL Serverに接続する
はじめに
複数人による開発でSQL Serverに接続できないかと考えました。
単純にEC2のポートを開けると不正にログインを試みるbotに耐えられずSQL Server が停止しまうため、踏み台サーバを経由した接続を行うことにしました。
全体像
A : 踏み台サーバ
B : データベースサーバ
A : 踏み台サーバ
SSH接続をする22番ポートを開けています。
またSSH接続用アカウントを新規作成しています。
今回はSSH.NETを使用してポートフォワーディングを行うため、踏み台サーバではポートフォワーディングの設定は行っていません。
B : データベースサーバ
SQL Serverの規定インスタンスに接続する1433番ポートを開けています。
ソースコード
C#からSSH接続が行えるSSH.NETを使用しました。
github.com
ソースコードはこちらです。
github.com
// 踏み台サーバのホスト名 string bastionServer = "XXXXXXXXXX"; // 踏み台サーバのアカウント名 string userName = "XXXXXXXXXX"; // 踏み台サーバのパスワード string password = "XXXXXXXXXX"; ConnectionInfo info = new ConnectionInfo(bastionServer, 22, userName, new AuthenticationMethod[] { new PasswordAuthenticationMethod(userName, password) } );
ForwardedPortLocal からポートフォワーディングを行っています。
// SQL Server 接続文字列 string connectionString = @"Data Source=127.0.0.1;Integrated Security=False;User ID=XXXXXXXXXX;Password=XXXXXXXXXX"; // データベースサーバのホスト名 string dbServer = "XXXXXXXXXX"; using (var client = new SshClient(info)) { client.Connect(); var forward = new ForwardedPortLocal("127.0.0.1", 1433, dbServer, 1433); client.AddForwardedPort(forward); forward.Start(); using (var connection = new SqlConnection(connectionString)) { using (var command = connection.CreateCommand()) { try { connection.Open(); connection.Open(); command.CommandText = @"SELECT count(*) AS count FROM employee";
結果
踏み台サーバを経由してSQL Server に接続する事ができました。
参考資料
C# で踏み台サーバー経由で RDS for MySQLに接続する方法 - 蒼の王座・裏口
Azure SQLDBにlinux踏み台サーバ経由で接続するには - Qiita
【SSH接続】Windows端末からパスワードなしでSSHログインする方法 | mathkuro
https://note.affi-sapo-sv.com/ssh-unprotected-key.php
Windows Server 2019 EC2インスタンスでSSHサーバーを有効にする | DevelopersIO
Windows/Linuxでポートフォワーディングする方法 - 備忘録
技術メモメモ: Windows Server 2019で標準サポートされた「OpenSSH」がすごく便利そうだった話
スマホにある子供の写真を親のLINEへ定期的に送ってみた
はじめに
コロナの影響で実家に帰れない為、子供の写真を親のLINEへ送っています。
しかし段々とLINEから送る事を手間に感じてしまい、送り忘れも増えました。
画像共有アプリの利用も考えましたが、アプリのインストール方法から親に説明する必要があるため、新しいアプリの利用は現実的な方法ではありません。
そこで写真を撮るだけで親のLINEに送れないかと考え、取り組むことにしました。
また無料で使えるサービスを組み合わせて実現することを目標にしました。
使ったサービス
- Google フォト
写真や動画をバックアップする - iPhone と iPad - Google フォト ヘルプ
ファイルを一般公開で共有する - Google Workspace ラーニング センター
Google Cloud Computing, Hosting Services & APIs
- Google Apps Script
【サンプルコード】GASでGoogleフォトの写真をドライブに日付ソート
- LINE Messaging API
料金
LINEに1日1枚の画像を送る程度であれば無料の範囲で実現できました。
- Google フォト
- Google ドライブ
容量15GBまで無料で使えます。
Google のストレージを追加購入する - パソコン - Google ドライブ ヘルプ
- Google クラウド
- Google Apps Script
APIも無料で使えます。
Google Drive Apis の利用に関して
- LINE Messaging API
フリープランを使用していて無料です。
料金プラン|LINE for Business
サービス間の連携
①画像を読み込む
子供の写真を撮影するスマホにGoogleフォトのアプリをインストールしています。
同期の設定によりスマホ内の写真はGoogleフォトのクラウドストレージに自動でバックアップされるので、Google Apps Scriptでその画像を毎朝9時に読み込みます。
②画像をコピー
Googleアカウントを持たない人にも共有する一般公開のフォルダにGoogleフォトの画像をコピーします。
一般公開とすることでLINEに画像の表示を可能にしています。
③メッセージの送信
Googleフォトにコピーした画像のURLをLINEに送信します。
画像のURLは外部から閲覧できるよう部分的に変更をしています。
④画像の表示
LINEを開くとGoogleドライブに保存していた画像が表示されます。
学び
①Googleドライブ
LINEに画像を表示するにはドライブのURLを変更する必要がありました。
ドライブのURLから画像にアクセスできるURLに変更しています。
var downloadURL = buff.getUrl().replace("/file/d/", "/uc?id=").replace("/view?usp=drivesdk", "")
【変更前】
https://drive.google.com/file/d/<ファイルID>/view?usp
【変更後】
https://drive.google.com/uc?id=<ファイルID>
②ダウンロードリンク
画像のURLに "=d" を付加すると画像のダウンロードリンクになります。
LINEで送った画像のダウンロードを可能にする為に必要でした。
③LINE Messaging API
画像を送るには imageThumbnail と imageFullSize を使用します。
変数downloadURLにGoogleドライブの画像のURLを格納しています。
var token = ["XXXXXXXXXXXXXXXX"]; //LINEで自動通知をする宛先のトークン。 var options = { "method" : "post", "payload" : {"message": "Today's photo.", "imageThumbnail" : downloadURL, "imageFullsize" : downloadURL, }, "headers" : {"Authorization" : "Bearer "+ token} }; UrlFetchApp.fetch("https://notify-api.line.me/api/notify", options);
結果
僕自身はLINEを使う事が無くなり写真を撮るだけで良くなりました。
なにより我が子の成長を母と兄に見てもらえて嬉しく思っています。
Run MVP sample app on the Android emulator
はじめに
2021年1月にAndroidアプリを開発する予定ができました。
何も知らない状態から20日で何が開発できるのか見当もつきませんが
まずはMVPアーキテクチャを学ぶことにしました。
MVPを選択した理由はMVCと似ていて分かりやすかったためです。
eh-career.com
MVPのサンプルをエミュレータで実行しようとしたのですが
一筋縄にはいかなかったため実行にあたり操作した内容をまとめます。
Download MVP sample app
リポジトリからソースコードをダウンロードします。
github.com
Android emulator HYPERVISOR_ERROR
エミュレータを実行すると HYPERVISOR_ERROR が発生する場合の対策です。
詳細な内容は以下を参照してください。
qiita.com
Qiitaを参考に私が実際に操作した内容になります。
プログラムと機能の削除 -> Windwosの機能の有効化または無効化
Hyper-V と Windowsハイパーバイザープラットフォーム のチェックを外します。
[OK]ボタンを押した後、変更を適用させるためにWindowsを必ず再起動します。
Android Studio を起動するとエミュレータの設定画面が表示されました。
メモリサイズは規定値の4GBを選択して次へ進みました。
インストール後のログにエラーが無いことを確認して完了です。
Encryption unsuccessful
エミュレータを実行すると Encryption unsuccessful になる場合の対策です。
tratail の回答が参考になりました。
teratail.com
使用するエミュレータで Wipe Data を実行します。
Run MVP sample app
MVPのサンプルを実行することが出来ました。
EC2 Ubuntu に Windows Subsystem for Linux (WSL1) からSSH接続する
はじめに
年末年始の休みを活用して改めてサーバ構築の勉強をしたいと思い
Ubuntu に Windows から SSH 接続できるようにしたので書き残します。
Ubuntu は EC2 に作成をしました。
SSH接続
調べてみると Windows から SSH 接続は簡単に出来るようです。
・Traterm
eng-entrance.com
・SSHクライアント
dev.classmethod.jp
・Windows Subsystem for Linux
www.atmarkit.co.jp
今回は Windows で Ubuntu が使える機能 Windows Subsystem for Linux (WSL1) をインストールして SSH 接続に使用することにしました。
WSLがあれば毎回 SSH 接続をしなくてもローカルでコマンドの確認が行えます。
Ubuntu EC2 インスタンスの作成
キーペアの作成までこちらのサイトが参考になりました。
www.acrovision.jp
Setup DB First EntityFrameworkCore SQL Server
はじめに
.Net Core で EntityFramework を使う際に .NET Standard と違って試行錯誤したのでDBファーストで使用した手順をまとめます。
対象のフレームワーク
今回は.NET Core 3.1を使用しました。
開発者用 PowerShell
コマンドは全て開発者用PowerShellから実行します。
カレントディレクトリはプロジェクトルートです。
PS C:\develop\WebApplication1\WebApplication1> dir ディレクトリ: C:\develop\WebApplication1\WebApplication1 Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 2020/12/20 17:30 bin d----- 2020/12/20 17:30 obj d----- 2020/12/20 17:29 Properties -a---- 2020/12/20 17:29 162 appsettings.Development.json -a---- 2020/12/20 17:29 192 appsettings.json -a---- 2020/12/20 17:30 723 Program.cs -a---- 2020/12/20 17:30 1295 Startup.cs -a---- 2020/12/20 17:29 148 WebApplication1.csproj
dotnet ef ツールのインストール
.NET Core 3.0 以降は .NET SDK に dotnet ef ツールが含まれていないため
初めて使用する場合はインストールが必要です。
dotnet tool update --global dotnet-ef
Microsoft.EntityFrameworkCore.Design の追加
スキャフォールディングに必要な Design パッケージを追加します。
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.EntityFrameworkCore.SqlServer の追加
スキャフォールディングに必要なデータベースプロバイダーを追加します。
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
Models フォルダの作成
コードを保存する Models フォルダを作成します。
スキャフォールディング
データベースから DBContext と Entity のコードを Models フォルダに作成します。
dotnet ef dbcontext scaffold "Server=[ホスト名];Database=[データベース名];persist security info=True;user id=[ユーザーID];password=[パスワード];MultipleActiveResultSets=True" Microsoft.EntityFrameworkCore.SqlServer -o Models
確認
EntityFrameworkCoreを使用してデータベースからコードが作成できました。
参考資料
Setup DB First EntityFramework SQLite
はじめに
SQLiteでEntityFrameworkのDBファーストを試してみました。
EntityFramework6 用の SQLiteToolBox DDEXプロバイダーを使用します。
ソリューションファイルの作成
サンプルとして Windows Form アプリケーションを作成しました。
1. SQLite Compact Toolbox のインストール
拡張機能の管理から SQLite/SQL Server Compact Toolbox をインストールします。
2. GAC に SQLite をインストール
sqlite-netFx46-setup-bundle-x86-2015-1.0.113.0.exe をダウンロードします。
デザイナコンポーネントは64bit版には含まれていないため32bit版を使用します。
GACにインストール、デザイナコンポーネントのインストールを選択します。
ちなみに64bit版のSetupだとデザイナーコンポーネントの選択がありません。
GACに登録されている事をToolboxから確認します。
3. System.Data.SQLite NuGet パッケージのインストール
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\machine.configの
DbProviderFactories タグからバージョン番号を確認します。
上記で確認したバージョン番号と同じ NuGet パッケージをインストールします。
NuGet Gallery | System.Data.SQLite 1.0.113.6
インストール後の packages.config
<?xml version="1.0" encoding="utf-8"?> <packages> <package id="EntityFramework" version="6.3.0" targetFramework="net48" /> <package id="Stub.System.Data.SQLite.Core.NetFramework" version="1.0.113.3" targetFramework="net48" /> <package id="System.Data.SQLite" version="1.0.113.0" targetFramework="net48" /> <package id="System.Data.SQLite.Core" version="1.0.113.6" targetFramework="net48" /> <package id="System.Data.SQLite.EF6" version="1.0.113.0" targetFramework="net48" /> <package id="System.Data.SQLite.Linq" version="1.0.113.0" targetFramework="net48" /> </packages>
インストール後の App.config
<?xml version="1.0" encoding="utf-8"?> <configuration> <configSections> <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --> <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> </configSections> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" /> </startup> <entityFramework> <providers> <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" /> <provider invariantName="System.Data.SQLite.EF6" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" /> </providers> </entityFramework> <system.data> <DbProviderFactories> <remove invariant="System.Data.SQLite.EF6" /> <add name="SQLite Data Provider (Entity Framework 6)" invariant="System.Data.SQLite.EF6" description=".NET Framework Data Provider for SQLite (Entity Framework 6)" type="System.Data.SQLite.EF6.SQLiteProviderFactory, System.Data.SQLite.EF6" /> <remove invariant="System.Data.SQLite" /><add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".NET Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" /></DbProviderFactories> </system.data> </configuration>
今回のApp.configには設定が不足している為 providers タグに設定を追加します。
変更後の App.config
<?xml version="1.0" encoding="utf-8"?> <configuration> <configSections> <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --> <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> </configSections> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" /> </startup> <entityFramework> <providers> <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" /> <provider invariantName="System.Data.SQLite.EF6" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" /> <provider invariantName="System.Data.SQLite" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" /> </providers> </entityFramework> <system.data> <DbProviderFactories> <remove invariant="System.Data.SQLite.EF6" /> <add name="SQLite Data Provider (Entity Framework 6)" invariant="System.Data.SQLite.EF6" description=".NET Framework Data Provider for SQLite (Entity Framework 6)" type="System.Data.SQLite.EF6.SQLiteProviderFactory, System.Data.SQLite.EF6" /> <remove invariant="System.Data.SQLite" /><add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".NET Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" /></DbProviderFactories> </system.data> <connectionStrings><add name="EmployeeDBContext" connectionString="data source=C:\Users\q612.TOHNICHI\source\repos\SQLiteEFSample\Employee.db" providerName="System.Data.SQLite.EF6" /></connectionStrings></configuration>
4. DBファーストの使用
DBファースト用に department テーブルを作成します。
DBの作成には DB Browser for SQLite を使用しました。
Downloads - DB Browser for SQLite
ADO.NET Entity Data Model を作成します。
データベースから Code First を選択します。
SQLite Provider (Simple for EF6 by ErikEJ) を使用します。
Data Source にDBのファイルパスを指定します。
テーブルを指定します。
Department と DBContext が作成されました。
全件検索した結果を一覧表示します。
using System; using System.Linq; using System.Windows.Forms; namespace SQLiteEFSample { using Model; public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { using (EmployeeDBContext context = new EmployeeDBContext()) { DataGridView.DataSource = context.Department.AsNoTracking().ToList(); } } } }
無事 department テーブルの一覧を表示する事ができました。
[:300]
補足 App.config の修正を行わなかった場合の動作
不足していた System.Data.SQLite を追加せず実行した場合の動作です。
<provider invariantName="System.Data.SQLite" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" />
SQLの発行を行う際に InvalidOperationException が発生します。
System.InvalidOperationException: 'No Entity Framework provider found for the ADO.NET provider with invariant name 'System.Data.SQLite'. Make sure the provider is registered in the 'entityFramework' section of the application config file. See http://go.microsoft.com/fwlink/?LinkId=260882 for more information.'