AppService(Web App for Containers)のはじめかたとSSHするまで

#概要
AppService(Web App for Containers)でsshするときに躓いたので備忘録的メモ。
※注意　長くなるけどイメージ作成から説明してます。

###もくじ

1. ファイル構成

1. Dockerイメージ作成

1. Azure Container Registory(ACR)作成

1. Azure Container Registory(ACR)にPush

1. AppServiceプロビジョニング

1. 参考文献

## 1. ファイル構成

```text
|--Dockerfile
|--init.sh
|--src
|  |--package.json
|  |--server.js
|--sshd_config
```

Dockerfileとプログラム起動用ファイル(init.sh),ssh設定ファイル(sshd_config),src配下のサンプルプログラムで構成されている。なお、サンプルプログラム言語をnodejsとしており、前提知識はここでは割愛。


## 2. Dockerイメージ作成

#### 各ファイル説明


**・Dockerfile** 

```dockerfile
FROM node:14

#ロケール,言語
ENV TZ Asia/Tokyo \
    LC_ALL en_US.UTF-8 \
    LANG en_US.UTF-8

#package.jsonをコピー,依存関係インストール
WORKDIR /usr/src
COPY ./src/package*.json ./
RUN npm install

#サンプルソースをコピー
COPY ./src/* ./

# ssh設定
# dialog,openssh-serverをインストール、パスワード変更を行う。
ENV SSH_PASSWD "root:Docker!"
RUN apt-get update \
        && apt-get install -y --no-install-recommends dialog \
        && apt-get update \
        && apt-get install -y --no-install-recommends openssh-server \
        && echo "$SSH_PASSWD" | chpasswd
# ssh用ファイルのコピー
COPY sshd_config /etc/ssh/

# プログラム起動用ファイルのコピーと権限付与
COPY init.sh /usr/local/bin/
RUN chmod u+x /usr/local/bin/init.sh

# コンテナのポート(8080をweb,2222をssh)
EXPOSE 8080 2222

# 実行コマンド指定
ENTRYPOINT ["init.sh"]
```

**注意点**
AppServiceのSSHポートは2222に設定されている必要アリ。

参考：SSH を有効にする
https://docs.microsoft.com/ja-jp/azure/app-service/configure-custom-container?pivots=container-linux





**・sshd_config** 
sshポートを2222に指定。

```bash
#
# /etc/ssh/sshd_config
#

Port                    2222
ListenAddress           0.0.0.0
LoginGraceTime          180
X11Forwarding           yes
Ciphers aes128-cbc,3des-cbc,aes256-cbc,aes128-ctr,aes192-ctr,aes256-ctr
MACs                    hmac-sha1,hmac-sha1-96
StrictModes             yes
SyslogFacility          DAEMON
PasswordAuthentication  yes
PermitEmptyPasswords    no
PermitRootLogin         yes
```

**・init.sh** 
sshとサンプルプログラムを起動。

```bash
#!/bin/bash
set -e

echo "Starting SSH ..."
service ssh start

node server.js
```



**・./src/server.js** 
Hello Worldを表示するだけのサンプルプログラム。

```javascript
'use strict';

const express = require('express');

// Constants
const PORT = 8080;
const HOST = '0.0.0.0';

// App
const app = express();
app.get('/', (req, res) => {
  res.send('Hello World');
});

app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);
```



**・./src/package.json** 

```json
{
  "name": "docker_web_app",
  "version": "1.0.0",
  "description": "Node.js on Docker",
  "author": "First Last <first.last@example.com>",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "express": "^4.16.1"
  }
}
```

#### docker image作成

Dockerfileが置かれているフォルダで以下実行(実行後ビルドが走る)

```bash
$　docker build . -t nodecontainer:1.0
```
作成されたイメージの確認

```bash
$ docker images
REPOSITORY                            TAG                 IMAGE ID            CREATED             SIZE
nodecontainer                         1.0                 15ba0530f316        8 minutes ago       969MB
```
コンテナ実行

```bash
$ docker run -d -p 8080:8080 nodecontainer:1.0
```

実行されているコンテナの確認

```bash
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                              NAMES
44aeff8c15c2        nodecontainer:1.0   "init.sh"           2 seconds ago       Up 2 seconds        2222/tcp, 0.0.0.0:8080->8080/tcp   focused_germain
```
試しに接続してみる。↓ちゃんとsshとサンプルプログラム実行されてるのでexitしておく。

```bash
$ docker exec -it focused_germain bash
$ ps aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  0.0  17952  2796 ?        Ss   Jun22   0:00 /bin/bash /usr/local/bin/init.sh
root          17  0.0  0.0  69964  3136 ?        Ss   Jun22   0:00 /usr/sbin/sshd
root          18  0.0  0.4 597024 37428 ?        Sl   Jun22   0:00 node server.js
root          45  0.3  0.0  18188  3128 pts/0    Ss   10:17   0:00 bash
root          50  0.0  0.0  36640  2876 pts/0    R+   10:17   0:00 ps aux
```

![acr4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540442/41621cc5-62d5-94ae-b3c5-734e5b9ce0c0.png)


## 3. Azure Container Registory(ACR)作成

#### ACR作成

Azure Portal を開いて
コンテナレジストリ > 作成
適当なサブスクリプション、リソースグループを指定しACRを作成する。
![acr1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540442/3f6608bb-4274-d2f6-27e8-f1c75bff7b46.png)

#### ACR設定

作成しただけではAppServiceにイメージ展開ができないため管理者ユーザを有効にする。
https://docs.microsoft.com/ja-jp/azure/container-registry/container-registry-authentication

コンテナレジストリ > 設定 > アクセスキー > 管理者ユーザ有効

![acr2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540442/6a493574-e6c7-e676-d1a9-1aeb41f09f00.png)


## 4. Azure Container Registory(ACR)にPush
docker imageをACRにpush

#### Azure CLIインストール
コマンドラインでAzureに接続するためにAzure CLIインストール。

```bash
$ curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
```

#### Azure Login
Azureにログイン

```bash
$ az login
```

#### サブスクリプション指定
サブスクリプションIDの調べ方は省略

```bash
$ az account set --subscription　{サブスクリプションID}
```

#### ACRに接続
作成したACRの
概要 > ログインサーバ
の値（※{acrのリソース名}.azurecr.io)をメモし以下実行。

```bash
az acr login --name {acrのリソース名}.azurecr.io
```

#### docker imageのタグ付け(ACR用)

```bash
docker tag nodecontainer:1.0  {acrのリソース名}.azurecr.io/nodecontainer:1.0
```

#### imageの確認 

```bash
$ docker images
REPOSITORY                                 TAG                 IMAGE ID            CREATED             SIZE
{acrのリソース名}.azurecr.io/nodecontainer   1.0                 15ba0530f316        15 hours ago        969MB
```

#### ACRにpush

```bash
$ docker push {acrのリソース名}.azurecr.io/nodecontainer:1.0
```

#### Azure Container Registoryをポータルで確認

コンテナレジストリ > サービス > リポジトリ

![acr3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540442/4ade9691-fa47-bd7c-d359-c6698fe68a26.png)


## 4. AppServiceプロビジョニング

![appservice1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540442/e5f9ee5b-0c6f-371a-9d11-a1b441c72988.png)

![appservice2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540442/cdfeee89-1d94-e6ce-91c4-00349d06f4e2.png)

#### AppServiceのポート設定

8080はデフォルトポートではないため
WEBSITE_PORTに8080を設定する(※保存しないと反映されないため注意)

![appservice3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540442/abc057fd-5bc0-7f41-ff23-e7f0ecb320f8.png)

起動されていることが確認できた

![appservice4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540442/0e41cf61-6d70-1e2d-aa69-d2634004bd00.png)


#### AppServiceにSSH接続

AppService > 開発ツール > SSH > 移動

![appservice5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540442/d4ac43c9-2d78-e82b-72d8-1cafc0e4b04a.png)

![appservice6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540442/a104e219-8250-6a9a-f083-838c871b966a.png)


## 5. 参考文献

https://docs.microsoft.com/ja-jp/azure/developer/javascript/how-to/deploy-containers
https://github.com/Azure-Samples/docker-django-webapp-linux