以下の内容はhttps://tech.guitarrapc.com/entry/2015/09/09/031236より取得しました。


Azure Web App のカスタムデプロイを使って特定のディレクトリをGitHubと同期する

Azureで一番好きなサービスはダントツでWeb Appです。以前はAzure WebSiteと呼ばれていました。やりすぎず、でも必要なことはできる。このバランス感が今でも崩れていないのはすごいです。

さて、Azureは各種SCMからのデプロイをサポートしており、そのデプロイ動作も制御できます。

今回は、カスタムデプロイを使って特定のGitHubディレクトリとWeb Appのディレクトリを同期する方法を見てみましょう。

何をするの

先日紹介した、OneGetのプライベートソースがありました。これを使ってデプロイの制御します。

https://tech.guitarrapc.com/entry/2015/09/04/042449

https://github.com/guitarrapc/MyOneGetServer

次の流れでやってみましょう。

  1. Web Appを起動しよう
  2. GitHubから継続的デプロイ連携*1を組む
  3. Kuduによる状態確認
  4. pushした変更の継続的デプロイ確認
  5. 一度連携を外して、別ブランチと連携し特定のディレクトリのみ同期する

継続的デプロイと合わせて、Kuduを使ってどう変化するか見てみましょう。

Web App を起動しよう

新ポータルで行います。旧ポータルでも余り操作は変わらないのでさくっと行きましょう。

新ポータルへ

https://portal.azure.comにアクセスして、

https://portal.azure.com

Microsoftアカウント、あるいは組織アカウントでログインします。ユーザー名のドメインに応じてそれぞれの画面にリダイレクトされます。

以前は旧ポータルがデフォルトでしたが、今ならログインすると新ポータルが見えます。

もし旧ポータルの場合は、右上のアカウントから Switch to Azure Preview Portal を選べばいいでしょう。

ログインでいつもはまるアレ

https://portal.azure.com は、ユーザー名のドメインに応じたリダイレクトをするのです。

が、Chromeだとちょくちょくリダイレクトに失敗してこけてそのまま身動きとれなくなるのはんぱなくストレスなのでいい加減直してほしいですね。*2

あと、Edgeだとちょくちょく#のみになったり、突然Office365にリダイレクトしようとして組織アカウントじゃないので起こられたりするのも。

Chromeの場合は、プライベートセッションにするとだいたいいけます。Edgeは、もう一度アドレスにhttps://portal.azure.com/?l=en&r=1を入れると今度は入れるのでほげー。

Web App を新規作成

今回はリソースマネージャーも使わず簡単にいきます。

New > Web + Mobile > Web App

おしまい。Virtual MachineやAWS EC2よりここは圧倒的に楽です。

今回は、AppName (つまりアクセス時のアドレスのためのサブドメイン)にguitarrapc-OneGet をつけました。これによりWeb Appの公開アドレスはhttps://guitarrapc-OneGet.azurewebsites.netとなります。

作成直後から、

30秒程度で利用可能になりました。いい素早さですね。

GitHub から継続的デプロイ連携を組む

旧ポータルでのWeb App作成だと、SCM*3デプロイの設定も作成時にでましたが完全ポータルでは今回出ませんでした。そこで、起動してあるWeb Appsに途中からデプロイを組んでみましょう。とはいえ、JenkinsやCircle CIも組む必要はなく、Visual Studioからの発行する必要もありません。

さっそく、Web Appの下にスクロールします。

Set up continuous deployment というのがあり、ここがSCMからの継続的デプロイ設定箇所です。開いてみましょう。

Microsoft Azure > guitarrapc-oneget > Continuous Deployment > Choose source といくと、連携可能なSCM一覧がでてきました。

Azure Web Appは、Visual Studio Online 以外にも、Git, GitHub, BitBucket, DropBpx, その他外部リポジトリ など各種SCMからの継続的デプロイが構成可能です。

今回はGitHubとの継続的デプロイを選択します。するとリポジトリのWebHookを受け取るためGitHubアカウントとの連携を求められるので、Authorizeから連携するユーザーで認証してください。*4

認証が終わったら、Choose Projectからデプロイするリポジトリを選択します。

今回は MyOneGetServer ですね。

最後に、ブランチをmasterにして完了です。

連携直後に最新コミットが自動デプロイされる

設定が完了すると、10秒ほど読み込みして

現在の状態が表示されます。リポジトリにまだpushしていないので、継続的デプロイは実行されていません。と思いきや? ?

継続的デプロイを設定すると直後に最新コミットがデプロイされます。

結果、先ほどのWeb Appのアドレスにアクセスすると、見事に表示されます。簡単素敵。

デプロイのログ

デプロイの結果を選択すると、デプロイ履歴が表示されます。履歴を選択すると、そのログが表示されます。さらにビルドログを選択することで詳細が表示されます。

これをみることで、nuget restoreの状態、MSBuildがいつ、どう動いたのかなどはログで簡単に追うことができます。

Kudu による状態確認

Azure Web Appが、PaaSとして強力なのはもちろんですが、なによりKuduの存在が大きいでしょう。

https://github.com/projectkudu/kudu

KuduはAzure Web AppのGitデプロイの裏のエンジンです。が、それだけでなく、Kuduを使うことで、Azure Web Appの中身や裏で何が起こっているのか。今どんな状態なのかまで、あたかもIaaSを扱うごとく容易に把握できます。

Kudu Services にアクセス

早速Kuduのポータルにアクセスします。Wikiにかかれている通り、公開されているWeb Appアドレスのドメインに.scmを差し込むだけです。

https://github.com/projectkudu/kudu/wiki/Accessing-the-kudu-service

例えば、https://guitarrapc-oneget.azurewebsites.net/なら、 https://guitarrapc-oneget.azurewebsites.net/となります。

見えましたね?

PowerShell でのデバッグコンソール

Kuduを使うことで、cmdかPowerShellをデバッグコンソールで扱えます。もちろんファイル操作もある程度可能です。

早速PowerShellのデバッグコンソールを開きましょう。Debug Console > PowerShell と進みます。

PowerShellコンソールがブラウザ上に表示されました。

表示されているパスが、基点となります。

Azure Web App の構成

ざっくり環境変数を見れば概要はつかめます。

https://gist.github.com/guitarrapc/18e3ca5219838d18e986

通常良く見るC:\ がシステムドライブな構成とは異なり、D:\ が基本です。あとは、もろもろ見えますが、それほど大きな差異はなくふつうに扱えますね。

Name                           Value
----                           -----
ALLUSERSPROFILE                D:\local\ProgramData
APP_POOL_CONFIG                C:\DWASFiles\Sites\#1guitarrapc-OneGet\Config...
APP_POOL_ID                    ~1guitarrapc-OneGet
APPDATA                        D:\local\AppData
APPSETTING_ScmType             GitHub
APPSETTING_WEBSITE_AUTH_ENA... False
APPSETTING_WEBSITE_NODE_DEF... 0.10.32
APPSETTING_WEBSITE_SITE_NAME   guitarrapc-OneGet
aspnet:DisableFcnDaclRead      true
aspnet:PortableCompilationO... true
aspnet:PortableCompilationO... Microsoft.Web.Compilation.Snapshots.SnapshotH...
AZURE_JETTY9_CMDLINE           -Djava.net.preferIPv4Stack=true -Djetty.port=...
AZURE_JETTY9_HOME              D:\Program Files (x86)\jetty-distribution-9.1...
AZURE_TOMCAT7_CMDLINE          -Dport.http=%HTTP_PLATFORM_PORT% -Djava.util....
AZURE_TOMCAT7_HOME             D:\Program Files (x86)\apache-tomcat-7.0.50
AZURE_TOMCAT8_CMDLINE          -Dport.http=%HTTP_PLATFORM_PORT% -Djava.util....
AZURE_TOMCAT8_HOME             D:\Program Files (x86)\apache-tomcat-8.0.23
branch                         master
CommonProgramFiles             D:\Program Files (x86)\Common Files
CommonProgramFiles(x86)        D:\Program Files (x86)\Common Files
CommonProgramW6432             D:\Program Files\Common Files
COMPUTERNAME                   RD00155E002C72
ComSpec                        D:\Windows\system32\cmd.exe
deployment_branch              master
DEPLOYMENT_SOURCE              D:\home
DEPLOYMENT_TARGET              D:\home\site\wwwroot
DIRCMD                         /OG /ON
EnableNuGetPackageRestore      true
FP_NO_HOST_CHECK               NO
GO_WEB_CONFIG_TEMPLATE         C:\Program Files (x86)\SiteExtensions\Kudu\47...
HOME                           D:\home
HOME_EXPANDED                  C:\DWASFiles\Sites\#1guitarrapc-OneGet\Virtua...
HOMEDRIVE                      D:
HOMEPATH                       \home
JAVA_HOME                      D:\Program Files\Java\jdk1.7.0_51
KUDU_SELECT_NODE_VERSION_CMD   node "C:\Program Files (x86)\SiteExtensions\K...
KUDU_SELECT_PYTHON_VERSION_CMD python "C:\Program Files (x86)\SiteExtensions...
KUDU_SYNC_CMD                  kudusync
LOCAL_EXPANDED                 C:\DWASFiles\Sites\#1guitarrapc-OneGet
LOCALAPPDATA                   D:\local\LocalAppData
MSBUILD_PATH                   D:\Windows\Microsoft.NET\Framework\v4.0.30319...
NPM_JS_PATH                    D:\Program Files (x86)\npm\1.4.28\node_module...
NUGET_EXE                      C:\Program Files (x86)\SiteExtensions\Kudu\47...
NUMBER_OF_PROCESSORS           8
OS                             Windows_NT
Path                           C:\Program Files (x86)\SiteExtensions\Kudu\47...
PATHEXT                        .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;....
POST_DEPLOYMENT_ACTION         postdeployment
POST_DEPLOYMENT_ACTIONS_DIR    D:\home\site\deployments\tools\PostDeployment...
PROCESSOR_ARCHITECTURE         x86
PROCESSOR_ARCHITEW6432         AMD64
PROCESSOR_IDENTIFIER           AMD64 Family 16 Model 8 Stepping 1, AuthenticAMD
PROCESSOR_LEVEL                16
PROCESSOR_REVISION             0801
ProgramData                    D:\local\ProgramData
ProgramFiles                   D:\Program Files (x86)
ProgramFiles(x86)              D:\Program Files (x86)
ProgramW6432                   D:\Program Files
PROMPT                         $P$G
PSModulePath                   WindowsPowerShell\Modules;D:\Program Files (x...
PUBLIC                         D:\Users\Public
REGION_NAME                    Japan West
REMOTEDEBUGGINGBITVERSION      vx86
REMOTEDEBUGGINGPORT
REWRITETABLE
SCM_BUILD_ARGS
SCM_COMMAND_IDLE_TIMEOUT       60
SCM_DNVM_PS_PATH               C:\Program Files (x86)\SiteExtensions\Kudu\47...
SCM_GIT_EMAIL                  windowsazure
SCM_GIT_USERNAME               windowsazure
SCM_LOGSTREAM_TIMEOUT          1800
SCM_TRACE_LEVEL                1
ScmType                        GitHub
SITE_BITNESS                   x86
SystemDrive                    D:
SystemRoot                     D:\Windows
TEMP                           D:\local\Temp
TMP                            D:\local\Temp
USERDOMAIN                     WORKGROUP
USERNAME                       RD00155E002C72$
USERPROFILE                    D:\local\UserProfile
WEBJOBS_DEPLOY_CMD             deploy_webjobs.cmd
webpages:Enabled               true
webpages:Version               3.0.0.0
WEBROOT_PATH                   D:\home\site\wwwroot
WEBSITE_AUTH_ENABLED           False
WEBSITE_COMPUTE_MODE           Shared
WEBSITE_HOSTNAME               guitarrapc-oneget.azurewebsites.net
WEBSITE_HTTPLOGGING_ENABLED    0
WEBSITE_IIS_SITE_NAME          ~1guitarrapc-OneGet
WEBSITE_INSTANCE_ID            24db6f195ef296845321623d224468be044afda818348...
WEBSITE_NODE_DEFAULT_VERSION   0.10.32
WEBSITE_OWNER_NAME             f6f639a1-58f5-4277-ac58-ee8bd698878d+japanwes...
WEBSITE_SCM_ALWAYS_ON_ENABLED  0
WEBSITE_SCM_SEPARATE_STATUS    1
WEBSITE_SITE_MODE              Limited
WEBSITE_SITE_NAME              guitarrapc-OneGet
WEBSITE_SKU                    Free
WEBSOCKET_CONCURRENT_REQUES... 5
windir                         D:\Windows
windows_tracing_flags
windows_tracing_logfile

継続的デプロイによるクローン先パス

リポジトリがクローンされるパスを知っておくのは、デプロイを弄るうえで大事です。

起点になるのは、$env:Home\Site\repositoryとなります。

PS D:\home> ls site


    Directory: D:\home\site


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----          9/8/2015   4:24 PM            deployments
d----          9/8/2015   4:57 PM            locks
d----          9/8/2015   4:24 PM            repository
d----          9/8/2015   4:24 PM            wwwroot

この辺の環境変数と合致しないのが腑に落ちないので、詳しい人の解説が欲しいですね。Kuduで監視する限り、RepositoryパスにCloneしているようにみえるのですが...。

deployment_branch              master
DEPLOYMENT_SOURCE              D:\home
DEPLOYMENT_TARGET              D:\home\site\wwwroot

アプリケーションが稼動するサイトパス

こちらもデプロイをいじるうえで必須です。

$env:\WEBROOT_PATH

となります。

デプロイによるリポジトリの変化をみる

パスがわかればこっちのものです。デプロイによって、クローンされたパスにファイルがあるか確認できますね。

先ほどのデプロイの時間と

クローンされたパスの時間、ビルド生成物をみれば一致していることがわかります。

https://gist.github.com/guitarrapc/3e4d56215361bc6c4588

PS D:\home> ls site/repository/MyOneGetServer


    Directory: D:\home\site\repository\MyOneGetServer


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----          9/8/2015   4:24 PM            App_Readme
d----          9/8/2015   4:24 PM            bin
d----          9/8/2015   4:24 PM            DataServices
d----          9/8/2015   4:24 PM            obj
d----          9/8/2015   4:24 PM            Properties
-a---          9/8/2015   4:24 PM       1952 Default.aspx
-a---          9/8/2015   4:24 PM      35561 favicon.ico
-a---          9/8/2015   4:24 PM       9588 MyOneGetServer.csproj
-a---          9/8/2015   4:24 PM        973 packages.config
-a---          9/8/2015   4:24 PM       5582 Web.config
-a---          9/8/2015   4:24 PM       1299 Web.Debug.config
-a---          9/8/2015   4:24 PM       1360 Web.Release.config


PS D:\home> ls site/repository/MyOneGetServer\bin


    Directory: D:\home\site\repository\MyOneGetServer\bin


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----          9/8/2015   4:24 PM            roslyn
-a---          9/8/2015   4:24 PM     176128 Elmah.dll
-a---          9/8/2015   4:24 PM      29344 Microsoft.CodeDom.Providers.DotNet
                                             CompilerPlatform.dll
-a---          9/8/2015   4:24 PM       1805 Microsoft.CodeDom.Providers.DotNet
                                             CompilerPlatform.xml
-a---          9/8/2015   4:24 PM      45416 Microsoft.Web.Infrastructure.dll
-a---          9/8/2015   4:24 PM      81600 Microsoft.Web.XmlTransform.dll
-a---          9/8/2015   4:24 PM       5120 MyOneGetServer.dll
-a---          9/8/2015   4:24 PM       5582 MyOneGetServer.dll.config
-a---          9/8/2015   4:24 PM      11776 MyOneGetServer.pdb
-a---          9/8/2015   4:24 PM     126976 Ninject.dll
-a---          9/8/2015   4:24 PM     384512 Ninject.pdb
-a---          9/8/2015   4:24 PM     325908 Ninject.xml
-a---          9/8/2015   4:24 PM     532656 NuGet.Core.dll
-a---          9/8/2015   4:24 PM      49840 NuGet.Server.dll
-a---          9/8/2015   4:24 PM      26624 RouteMagic.dll
-a---          9/8/2015   4:24 PM      10752 WebActivatorEx.dll

デプロイによるサイトの変化をみる

同様にサイトもわかりますね。リポジトリの生成物と一致しているはずです。

https://gist.github.com/guitarrapc/9dc2376898412eeba7d8

PS D:\home> ls site/wwwroot


    Directory: D:\home\site\wwwroot


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----          9/8/2015   4:24 PM            App_Readme
d----          9/8/2015   4:24 PM            bin
d----          9/8/2015   4:24 PM            DataServices
-a---          9/8/2015   4:24 PM       1952 Default.aspx
-a---          9/8/2015   4:24 PM      35561 favicon.ico
-a---          9/8/2015   4:24 PM        973 packages.config
-a---          9/8/2015   4:24 PM       5569 Web.config


PS D:\home> ls site/wwwroot/bin


    Directory: D:\home\site\wwwroot\bin


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----          9/8/2015   4:24 PM            roslyn
-a---          9/8/2015   4:24 PM     176128 Elmah.dll
-a---          9/8/2015   4:24 PM      29344 Microsoft.CodeDom.Providers.DotNet
                                             CompilerPlatform.dll
-a---          9/8/2015   4:24 PM      45416 Microsoft.Web.Infrastructure.dll
-a---          9/8/2015   4:24 PM      81600 Microsoft.Web.XmlTransform.dll
-a---          9/8/2015   4:24 PM       5120 MyOneGetServer.dll
-a---          9/8/2015   4:24 PM     126976 Ninject.dll
-a---          9/8/2015   4:24 PM     532656 NuGet.Core.dll
-a---          9/8/2015   4:24 PM      49840 NuGet.Server.dll
-a---          9/8/2015   4:24 PM      26624 RouteMagic.dll
-a---          9/8/2015   4:24 PM      10752 WebActivatorEx.dll

意図通りにデプロイされていますね。

push した変更の継続的デプロイ確認

さて、継続デプロイということは、SCMと連携して変更が自動的にWeb Appにデプロイされるはずです。

GitHubの場合は、Webhookを使っており、pushのイベントを受けると自動デプロイされます。早速、masterにテストコミットをします。*5

これをpushすると?

即座にGitHubからWebhookが飛び、Web Appでデプロイが開始されました。

デプロイが完了して、Activeなバージョンが更新されていますね。

Kudu での確認

kuduで変更が反映されたか見てみましょう。

意図した通り、変更したReadme.mdのみが更新されています。

PS D:\home> ls site/repository


    Directory: D:\home\site\repository


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----          9/8/2015   4:24 PM            MyOneGetServer
d----          9/8/2015   4:24 PM            MyOneGetServer.Script
d----          9/8/2015   4:24 PM            packages
-a---          9/8/2015   4:24 PM       2581 .gitattributes
-a---          9/8/2015   4:24 PM       3412 .gitignore
-a---          9/8/2015   4:24 PM        224 .gitmodules
-a---          9/8/2015   4:24 PM       1526 MyOneGetServer.sln
-a---          9/8/2015   5:16 PM        393 README.md

一度連携を外して、別ブランチと連携し特定のディレクトリのみ同期する

さてようやく本題です。

このGitHubでの継続デプロイは、このままだとWeb SiteのコンテンツがGitHubのビルド結果と同一になってしまいます。

しかし現実にはこれでは困るシーンがいくつかあります。例えば、WordPressをホスティングしており、一部のWordPress管理外の静的ファイルのみGitHubと連動させたい場合を考えます。

  • 丸ごとGitHubと同期されては困る
  • デプロイのフローに特殊な処理をはさみ込みたい場合も、デプロイを調整
  • プライベートNuGetサーバーからライブラリを取得

そこで出てくるのが、カスタムデプロイです。

参考

参考にするのは、KuduのWikiとChannel 9です。

https://github.com/projectkudu/kudu/wiki/Customizing-deployments

https://azure.microsoft.com/ja-jp/documentation/videos/custom-web-site-deployment-scripts-with-kudu/

Custom Deploy の概要

どこのサイトをみてもざっくりと誰も書いていないのですが、単純です。*6

  • リポジトリ直下に.deploymentファイルがあると、そこの.deployment属性に書かれた.deploymentのコマンドを実行
  • .deploymentから、別のcmdや.ps1を呼び出すことも可能でより複雑な処理を書くこともできる

たったこれだけです。早速MyOneGetServerのリポジトリで、試してみましょう。

カスタムデプロイ構成

やることは単純です。

  • MyOneGetServer.Scriptフォルダを、wwwroot直下に同期する

これを行うために以下の構成にします。

  • .deploymentファイルを作成する
  • BuildScript\deploy.ps1で同期処理を記述する
  • 一度継続的デプロイ連携を切る
  • 変更をpushする
  • 再度継続デプロイを連携してカスタムデプロイの確認

この.deploymentに記述された内容だけ実施されるのはとても大事です。何しろ継続的デプロイ連携をした瞬間にデプロイされるので、事前に.deploymentの内容だけ実施されるとわかっていれば、運用中のアプリを壊す心配がなくなります。

.deploy ファイルの作成

とりあえず、さくっと作ります。

https://gist.github.com/guitarrapc/aa1c303d39e96b909633

できましたね。

続いて、BuildScript\deploy.ps1を実行するようにします。

https://gist.github.com/guitarrapc/9f6f3f34cfb01186bd98

今回のように、PowerShellスクリプトを実行する場合は、-ExecutionPolicy RemoteSignedを指定しましょう。でないと、デフォルトが-ExecutionPolicy RemoteSignedになっており、.ps1が実行できません。

BuildScript\deploy.ps1 の記述

続いて、BuildScript\deploy.ps1を作成します。

https://gist.github.com/guitarrapc/921f664444a74ca0783f

同期内容を記述します。

同期処理には注意です。Azure Web Appsのデプロイ過程では、Web Deploymentを呼び出してもエラーが出ます。

kuduでも実行できないことが確認できます。

そのため、PowerShellで頑張らずとも、ここはRoboCopyを使って同期処理を書きましょう。

https://gist.github.com/guitarrapc/178197ad7098696b53aa

ポイントは、try{}catch{}でのtry{}catch{}処理です。PowerShellは、cmdなどからの外部呼び出しでふつーにエラーをだしても終了コードは1のままです。

そこで、明示的にエラーを外部に通知するためには、終了コードとともに終了させる必要があります。*7今回は、エラーを起こす可能性のある、RoboCopyの処理でのエラーを捉えるようにしています。

これで準備は完了しました。

一度継続的デプロイ連携を切る

それでは、すでに存在するアプリケーションでのSCM連携を模擬するため、一度連携を切ります。

連携は、Disconnectを選択することで切れます。

実行すると無事に切れましたね。

連携を切っても、連携してたアプリが消えるわけではないので安心してください。

変更を push する

それでは、先ほどの.deployment.deploymentをpushします。

https://github.com/guitarrapc/MyOneGetServer/commit/6ed0a71bfd5c00329ce615b416455c48afa1cd21

再度継続デプロイを連携してカスタムデプロイの確認

連携したときのデプロイが、「カスタムデプロイがない時のビルド結果のデプロイ」ではなく「deploy.ps1で記述したカスタムデプロイ処理のみ実施」されればokです。

さくっと連携します。

デプロイがキックされます。

ログを見ると、うまくいってそうですね。

kuduでみると、連携前のフォルダ構成に、

意図した通りMyOneGetServer.Scriptが増えていますね。

まとめ

いかがでしたでしょうか? Azure Web App最高ですね。継続的デプロイがCIいらずでここまで簡単にできるのは、.NETではなかなか難しいものです。AppVeyorとかもふつーにCIでつらいですしね。

カスタムデプロイやkuduでの確認も簡単です。

ぜひぜひ使ってみてください。

*1:継続的デリバリーでもどっちでも表現はお好きに

*2:Azureが利用できるようになってから数年たってもなおらないしCookie、セッション削除でもダメなの辛い

*3:Source Code Management : ソースコードの管理基盤を指します。GitやGitHub、Subversionが有名ですね

*4:新ポータルでは新しいウィンドウを開くことなく連携できますが、旧ポータルでは別ウィンドウが裏で開くので気づき辛いのが悲しいですね

*5:本当は別ブランチでやりたかったけどいいです

*6:こういう基礎中の基礎を誰も書いてないの謎

*7:throwではだめということです




以上の内容はhttps://tech.guitarrapc.com/entry/2015/09/09/031236より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14