GIG

赴くままに技術を。

Azure Disk Enclyptionを有効化したOSディスクの拡張

Azure Disk Encryption(ADE)で暗号化されたOSディスクを拡張する手順についてメモ。

前提
  • 暗号化された OS ディスクのサイズ変更はサポート外のため自己責任

learn.microsoft.com

OS パーティションのサイズは変更できますか? ADE で暗号化された OS ディスクのサイズは現在のところ変更できません。

確認

対象仮想マシンを展開して、既定ではOSディスクサイズが64GiBであることを確認

# df -h
Filesystem                 Size  Used Avail Use% Mounted on
devtmpfs                   3.9G     0  3.9G   0% /dev
tmpfs                      3.9G     0  3.9G   0% /dev/shm
tmpfs                      3.9G  9.1M  3.9G   1% /run
tmpfs                      3.9G     0  3.9G   0% /sys/fs/cgroup
/dev/mapper/rootvg-rootlv  2.0G   70M  2.0G   4% /
/dev/mapper/rootvg-usrlv    10G  1.5G  8.6G  15% /usr
/dev/sda2                  494M  153M  342M  31% /boot
/dev/mapper/rootvg-homelv 1014M   33M  982M   4% /home
/dev/mapper/rootvg-optlv   2.0G  140M  1.9G   7% /opt
/dev/mapper/rootvg-tmplv   2.0G   33M  2.0G   2% /tmp
/dev/sda1                  500M  9.9M  490M   2% /boot/efi
/dev/mapper/rootvg-varlv   8.0G  185M  7.9G   3% /var
/dev/sdb1                   16G   45M   15G   1% /mnt
/dev/sdc1                   42M  1.5K   42M   1% /mnt/azure_bek_disk
tmpfs                      783M     0  783M   0% /run/user/1000
# lsblk
NAME                MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINT
sda                   8:0    0   64G  0 disk
├─sda1                8:1    0  500M  0 part  /boot/efi
├─sda2                8:2    0  500M  0 part  /boot
├─sda3                8:3    0    2M  0 part
└─sda4                8:4    0   63G  0 part
  └─osencrypt       253:0    0   63G  0 crypt
    ├─rootvg-tmplv  253:1    0    2G  0 lvm   /tmp
    ├─rootvg-usrlv  253:2    0   10G  0 lvm   /usr
    ├─rootvg-optlv  253:3    0    2G  0 lvm   /opt
    ├─rootvg-homelv 253:4    0    1G  0 lvm   /home
    ├─rootvg-varlv  253:5    0    8G  0 lvm   /var
    └─rootvg-rootlv 253:6    0    2G  0 lvm   /
sdb                   8:16   0   16G  0 disk
└─sdb1                8:17   0   16G  0 part  /mnt
sdc                   8:32   0   48M  0 disk
└─sdc1                8:33   0   46M  0 part  /mnt/azure_bek_disk

ディスクサイズを変更するためAzureポータルより仮想マシンを停止(割り当て解除)し、その後OSディスクを選択して、サイズを変更 (今回は64GiBから128GiBに変更)を実施する。 その後仮想マシンを起動する。

パーティションを拡張する。

# lsblk
NAME                MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINT
sda                   8:0    0  128G  0 disk
├─sda1                8:1    0  500M  0 part  /boot/efi
├─sda2                8:2    0  500M  0 part  /boot
├─sda3                8:3    0    2M  0 part
└─sda4                8:4    0   63G  0 part
  └─osencrypt       253:0    0   63G  0 crypt
    ├─rootvg-tmplv  253:1    0    2G  0 lvm   /tmp
    ├─rootvg-usrlv  253:2    0   10G  0 lvm   /usr
    ├─rootvg-optlv  253:3    0    2G  0 lvm   /opt
    ├─rootvg-homelv 253:4    0    1G  0 lvm   /home
    ├─rootvg-varlv  253:5    0    8G  0 lvm   /var
    └─rootvg-rootlv 253:6    0    2G  0 lvm   /
sdb                   8:16   0   16G  0 disk
└─sdb1                8:17   0   16G  0 part  /mnt
sdc                   8:32   0   48M  0 disk
└─sdc1                8:33   0   46M  0 part  /mnt/azure_bek_disk
# growpart /dev/sda 4
CHANGED: partition=4 start=2054144 old: size=132161536 end=134215680 new: size=266381278 end=268435422
# lsblk
NAME                MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINT
sda                   8:0    0  128G  0 disk
├─sda1                8:1    0  500M  0 part  /boot/efi
├─sda2                8:2    0  500M  0 part  /boot
├─sda3                8:3    0    2M  0 part
└─sda4                8:4    0  127G  0 part
  └─osencrypt       253:0    0   63G  0 crypt
    ├─rootvg-tmplv  253:1    0    2G  0 lvm   /tmp
    ├─rootvg-usrlv  253:2    0   10G  0 lvm   /usr
    ├─rootvg-optlv  253:3    0    2G  0 lvm   /opt
    ├─rootvg-homelv 253:4    0    1G  0 lvm   /home
    ├─rootvg-varlv  253:5    0    8G  0 lvm   /var
    └─rootvg-rootlv 253:6    0    2G  0 lvm   /
sdb                   8:16   0   16G  0 disk
└─sdb1                8:17   0   16G  0 part  /mnt
sdc                   8:32   0   48M  0 disk
└─sdc1                8:33   0   46M  0 part  /mnt/azure_bek_disk

暗号化された領域を拡張する。

[root@labrhellvm ~]# cryptsetup resize /dev/mapper/osencrypt
[root@labrhellvm ~]# lsblk
NAME                MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINT
sda                   8:0    0  128G  0 disk
├─sda1                8:1    0  500M  0 part  /boot/efi
├─sda2                8:2    0  500M  0 part  /boot
├─sda3                8:3    0    2M  0 part
└─sda4                8:4    0  127G  0 part
  └─osencrypt       253:0    0   63G  0 crypt
    ├─rootvg-tmplv  253:1    0    2G  0 lvm   /tmp
    ├─rootvg-usrlv  253:2    0   10G  0 lvm   /usr
    ├─rootvg-optlv  253:3    0    2G  0 lvm   /opt
    ├─rootvg-homelv 253:4    0    1G  0 lvm   /home
    ├─rootvg-varlv  253:5    0    8G  0 lvm   /var
    └─rootvg-rootlv 253:6    0    2G  0 lvm   /
sdb                   8:16   0   16G  0 disk
└─sdb1                8:17   0   16G  0 part  /mnt
sdc                   8:32   0   48M  0 disk
└─sdc1                8:33   0   46M  0 part  /mnt/azure_bek_disk
[root@labrhellvm ~]# pvs
  PV                    VG     Fmt  Attr PSize   PFree
  /dev/mapper/osencrypt rootvg lvm2 a--  <63.02g <38.02g
[root@labrhellvm ~]# pvresize /dev/mapper/osencrypt
  Physical volume "/dev/mapper/osencrypt" changed
  1 physical volume(s) resized or updated / 0 physical volume(s) not resized
[root@labrhellvm ~]# pvs
  PV                    VG     Fmt  Attr PSize   PFree
  /dev/mapper/osencrypt rootvg lvm2 a--  <63.02g <38.02g

再起動して反映される確認する。

[root@labrhellvm ~]# pvs
  PV                    VG     Fmt  Attr PSize   PFree
  /dev/mapper/osencrypt rootvg lvm2 a--  <63.02g <38.02g

変わらないので、再度PVを拡張すると、128 GiB まで拡張された。

[root@labrhellvm ~]# pvresize /dev/mapper/osencrypt
  Physical volume "/dev/mapper/osencrypt" changed
  1 physical volume(s) resized or updated / 0 physical volume(s) not resized
[root@labrhellvm ~]# pvs
  PV                    VG     Fmt  Attr PSize    PFree
  /dev/mapper/osencrypt rootvg lvm2 a--  <127.02g <102.02g

root ("/") に全振りしてみる。

# lvs
  LV     VG     Attr       LSize  Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  homelv rootvg -wi-ao----  1.00g
  optlv  rootvg -wi-ao----  2.00g
  rootlv rootvg -wi-ao----  2.00g
  tmplv  rootvg -wi-ao----  2.00g
  usrlv  rootvg -wi-ao---- 10.00g
  varlv  rootvg -wi-ao----  8.00g
# lvextend -l 100%FREE /dev/rootvg/rootlv
  Size of logical volume rootvg/rootlv changed from 2.00 GiB (512 extents) to <102.02 GiB (26116 extents).
  Logical volume rootvg/rootlv successfully resized.
# lvs
  LV     VG     Attr       LSize    Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  homelv rootvg -wi-ao----    1.00g
  optlv  rootvg -wi-ao----    2.00g
  rootlv rootvg -wi-ao---- <102.02g
  tmplv  rootvg -wi-ao----    2.00g
  usrlv  rootvg -wi-ao----   10.00g
  varlv  rootvg -wi-ao----    8.00g

最後に対象LV上のファイルシステムを拡張する。

# df -h
Filesystem                 Size  Used Avail Use% Mounted on
devtmpfs                   3.9G     0  3.9G   0% /dev
tmpfs                      3.9G     0  3.9G   0% /dev/shm
tmpfs                      3.9G  9.1M  3.9G   1% /run
tmpfs                      3.9G     0  3.9G   0% /sys/fs/cgroup
/dev/mapper/rootvg-rootlv  2.0G   70M  2.0G   4% /
/dev/mapper/rootvg-usrlv    10G  1.5G  8.6G  15% /usr
/dev/sda2                  494M  153M  342M  31% /boot
/dev/sda1                  500M  9.9M  490M   2% /boot/efi
/dev/mapper/rootvg-homelv 1014M   33M  982M   4% /home
/dev/mapper/rootvg-tmplv   2.0G   33M  2.0G   2% /tmp
/dev/mapper/rootvg-optlv   2.0G  140M  1.9G   7% /opt
/dev/mapper/rootvg-varlv   8.0G  186M  7.9G   3% /var
/dev/sdb1                   16G   45M   15G   1% /mnt
/dev/sdc1                   42M  1.5K   42M   1% /mnt/azure_bek_disk
tmpfs                      783M     0  783M   0% /run/user/1000
# xfs_growfs /
meta-data=/dev/mapper/rootvg-rootlv isize=512    agcount=4, agsize=131072 blks
         =                       sectsz=4096  attr=2, projid32bit=1
         =                       crc=1        finobt=0 spinodes=0
data     =                       bsize=4096   blocks=524288, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
log      =internal               bsize=4096   blocks=2560, version=2
         =                       sectsz=4096  sunit=1 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
data blocks changed from 524288 to 26742784
# df -h
Filesystem                 Size  Used Avail Use% Mounted on
devtmpfs                   3.9G     0  3.9G   0% /dev
tmpfs                      3.9G     0  3.9G   0% /dev/shm
tmpfs                      3.9G  9.1M  3.9G   1% /run
tmpfs                      3.9G     0  3.9G   0% /sys/fs/cgroup
/dev/mapper/rootvg-rootlv  103G   82M  102G   1% /
/dev/mapper/rootvg-usrlv    10G  1.5G  8.6G  15% /usr
/dev/sda2                  494M  153M  342M  31% /boot
/dev/sda1                  500M  9.9M  490M   2% /boot/efi
/dev/mapper/rootvg-homelv 1014M   33M  982M   4% /home
/dev/mapper/rootvg-tmplv   2.0G   33M  2.0G   2% /tmp
/dev/mapper/rootvg-optlv   2.0G  140M  1.9G   7% /opt
/dev/mapper/rootvg-varlv   8.0G  184M  7.9G   3% /var
/dev/sdb1                   16G   45M   15G   1% /mnt
/dev/sdc1                   42M  1.5K   42M   1% /mnt/azure_bek_disk
tmpfs                      783M     0  783M   0% /run/user/1000

AzureAD認証で異なるテナント間のBlobコピー

ドキュメントには特段記載がないと思っていたところ、現在のところサポートされないシナリオでした。

AzCopy v10 を使用して Azure ストレージ アカウント間で BLOB をコピーする | Microsoft Learn

移行元アカウントと移行先アカウントは、同じ Azure AD テナントに属している必要があります。


一応、行うとどんなエラーとなるかメモ。

事前準備

-テナントAでストレージ アカウントを作成 -テナントBでストレージアカウントを作成 -ダミーファイル (1MB) を複数作成し、テナントAのストレージアカウントにアップロード

for /l %n in (1,1,3000) do fsutil file createnew %n 1048576

-操作アカウントに対して、以下のRBACを付与 - テナントAストレージアカウント; ストレージBLOBデータ閲覧者 - テナントBストレージアカウント; ストレージBLOB共同作成者

コピーの実行
PS > azcopy login --tenant-id "aaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code XXXXXXXXX to authenticate.

INFO: Login succeeded.
PS > azcopy login --tenant-id "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code XXXXXXXXX to authenticate.

INFO: Login succeeded.

azcopy copyを実行すると、どうやらデータコピー元に対して参照操作が認証エラー

PS > azcopy copy "https://<src>.blob.core.windows.net/src/testdata" "https://<dest>.blob.core.windows.net/dest" --recursive
INFO: Scanning...
INFO: Authenticating to destination using Azure AD
INFO: Authenticating to source using Azure AD
INFO: Any empty folders will not be processed, because source and/or destination doesn't have full folder support

failed to perform copy command due to error: cannot start job due to error: cannot list files due to reason -> github.com/Azure/azure-storage-blob-go/azblob.newStorageError, /home/vsts/go/pkg/mod/github.com/!azure/azure-storage-blob-go@v0.15.0/azblob/zc_storage_error.go:42
===== RESPONSE ERROR (ServiceCode=InvalidAuthenticationInfo) =====
Description=Server failed to authenticate the request. Please refer to the information in the www-authenticate header.
RequestId:39925b77-701e-0041-5a55-06a0e8000000
Time:2022-12-02T13:56:13.9916736Z, Details:
   AuthenticationErrorDetail: Issuer validation failed. Issuer did not match.
   Code: InvalidAuthenticationInfo
   GET https://<src>.blob.core.windows.net/src?comp=list&delimiter=%2F&include=metadata&prefix=testdata%2F&restype=container&timeout=901
   Authorization: REDACTED
   User-Agent: [AzCopy/10.16.2 Azure-Storage/0.15 (go1.17.9; Windows_NT)]
   X-Ms-Client-Request-Id: [833ede1e-8e87-4dbc-6777-f49b2fdb66e6]
   X-Ms-Version: [2020-10-02]
   --------------------------------------------------------------------------------
   RESPONSE Status: 401 Server failed to authenticate the request. Please refer to the information in the www-authenticate header.
   Content-Length: [402]
   Content-Type: [application/xml]
   Date: [Fri, 02 Dec 2022 13:56:13 GMT]
   Server: [Microsoft-HTTPAPI/2.0]
   Www-Authenticate: [Bearer authorization_uri=https://login.microsoftonline.com/72f988bf-86f1-41af-91ab-2d7cd011db47/oauth2/authorize resource_id=https://storage.azure.com]
   X-Ms-Error-Code: [InvalidAuthenticationInfo]
   X-Ms-Request-Id: [39925b77-701e-0041-5a55-06a0e8000000]

下記の開発元からのコメントにあるように、現時点では非サポートの状況

Azcopy Copy - Supported directions missing | Azure Blob (OAuth authentication) -> Azure Blob (OAuth authentication) · Issue #99148 · MicrosoftDocs/azure-docs · GitHub

回避策

コピー元、コピー先のストレージアカウントのどちらかのみに対しAzure AD認証を使うのはOKなので、もう一方は例えばSAS使ってコピーができます。

テナントA (Azure AD) -> テナントB (SAS)

コピー先のコンテナーに対して、SASトークンを発行 (アクセス許可 : 作成)

PS > azcopy login --tenant-id "aaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code XXXXXXXXX to authenticate.

INFO: Login succeeded.
PS > azcopy copy "https://<src>.blob.core.windows.net/src/testdata" "https://<dest>.blob.core.windows.net/dest?sp=c&st=2022-12-03T07:24:55Z&se=2022-12-03T15:24:55Z&spr=https&sv=2021-06-08&sr=c&sig=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" --recursive
INFO: Scanning...
INFO: Authenticating to source using Azure AD
INFO: Failed to create one or more destination container(s). Your transfers may still succeed if the container already exists.
INFO: Any empty folders will not be processed, because source and/or destination doesn't have full folder support

Job ef855a5f-2cd9-174f-6bc2-d0f8aab4798f has started
Log file is located at: C:\Users\<user>\.azcopy\ef855a5f-2cd9-174f-6bc2-d0f8aab4798f.log

INFO: Could not read destination length. If the destination is write-only, use --check-length=false on the command line.
100.0 %, 3000 Done, 0 Failed, 0 Pending, 0 Skipped, 3000 Total, 2-sec Throughput (Mb/s): 2707.3708


Job ef855a5f-2cd9-174f-6bc2-d0f8aab4798f summary
Elapsed Time (Minutes): 0.1001
Number of File Transfers: 3000
Number of Folder Property Transfers: 0
Total Number of Transfers: 3000
Number of Transfers Completed: 3000
Number of Transfers Failed: 0
Number of Transfers Skipped: 0
TotalBytesTransferred: 3145728000
Final Job Status: Completed

テナントA (SAS) -> テナントB (Azure AD)

コピー元のコンテナーに対して、SASトークンを発行 (アクセス許可 : 読み取り/リスト)

PS > azcopy login --tenant-id "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code XXXXXXXXX to authenticate.

INFO: Login succeeded.
PS > azcopy copy "https://<src>.blob.core.windows.net/src?sp=rl&st=2022-12-03T07:31:27Z&se=2022-12-03T15:31:27Z&spr=https&sv=2021-06-08&sr=c&sig=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "https://<dest>.blob.core.windows.net/dest" --recursive
INFO: Scanning...
INFO: Authenticating to destination using Azure AD
INFO: Authentication: If the source and destination accounts are in the same AAD tenant & the user/spn/msi has appropriate permissions on both, the source SAS token is not required and OAuth can be used round-trip.
INFO: Any empty folders will not be processed, because source and/or destination doesn't have full folder support

Job 37be841c-fb7a-f048-603d-33b3c1d44aa2 has started
Log file is located at: C:\Users\<user>\.azcopy\37be841c-fb7a-f048-603d-33b3c1d44aa2.log

INFO: Transfers could fail because AzCopy could not verify if the destination supports tiers.
100.0 %, 3000 Done, 0 Failed, 0 Pending, 0 Skipped, 3000 Total, 2-sec Throughput (Mb/s): 4798.4101


Job 37be841c-fb7a-f048-603d-33b3c1d44aa2 summary
Elapsed Time (Minutes): 0.1005
Number of File Transfers: 3000
Number of Folder Property Transfers: 0
Total Number of Transfers: 3000
Number of Transfers Completed: 3000
Number of Transfers Failed: 0
Number of Transfers Skipped: 0
TotalBytesTransferred: 3145728000
Final Job Status: Completed

プライベートコンテナレジストリ(Harbor)を構築

Azure CLIベースでHarborの構築メモ。 流れとしては以下となります。

  1. コンテナレジストをデプロイするVNetを作成 2.コンテナレジストリを構築 3.踏み台サーバにGUI環境を構築しHarborにアクセス 4.DockerイメージをHarborにプッシュ
1. コンテナレジストをデプロイするVNetを作成

リソースグループを作成

az group create --name labprivcr --location japaneast

次に仮想ネットワークとサブネットを作成

$ az network vnet create --resource-group labprivcr --name vnetforprivcr --address-prefixes 10.0.0.0/16 --subnet-name subnet1 --subnet-prefixes 10.0.0.0/24
2.コンテナレジストリを構築

要件を見ると、4 CPU / メモリ 8GB / ディスク 160 GB とあるので、B4ms サイズ (4 vCPU / 16 Gib メモリ) を選択 Harbor docs | Harbor Installation Prerequisites

Harbor 用に仮想マシンを作成 ローカルでのみ利用する想定なので、パブリックIPアドレスは付与していません。

$ az vm create --resource-group labprivcr --name privcr --image UbuntuLTS --vnet-name vnetforprivcr --subnet subnet1 --admin-username azureuser --ssh-key-values ~/.ssh/id_rsa.pub --public-ip-address "" --size Standard_B4ms

プライベートDNSゾーンを設定し、仮想ネットワークにリンク。 az network private-dns link vnet create の際に、--registration-enabled false としているのは、後々 VNetピアリングしたとき、そこにデプロイしたAKSノードも登録されてしまうため、必要なものだけ登録するよう、falseを設定しています。

$ az network private-dns zone create --resource-group labprivcr --name labprivcr.com
$ az network private-dns link vnet create --resource-group labprivcr --name labprivcrlink --zone-name labprivcr.com --virtual-network vnetforprivcr --registration-enabled false
$ az network private-dns record-set a add-record --resoruce-group labprivcr --zone-name labprivcr.com --record-set-name privcr --ipv4-address 10.0.0.4

踏み台サーバをデプロイ こちらはパブリックIPアドレスを付与します。

$ az vm create --resource-group labprivcr --name jumpbox --image UbuntuLTS --vnet-name vnetforprivcr --subnet subnet1 --admin-username azureuser --ssh-key-values ~/.ssh/id_rsa.pub

踏み台サーバがデプロイできたら、踏み台サーバ→プライベートコンテナレジストリVMSSH接続します。

$ scp -p ~/.ssh/id_rsa azureuser@xxx.xxx.xxx.xxx:/home/azureuser/.ssh/
$ ssh azureuser@xxx.xxx.xxx.xxx
$ ssh azureuser@privcr

Dockerをインストール

参考; Install Docker Engine on Ubuntu | Docker Documentation

$ sudo apt-get update
$ sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo apt-key fingerprint 0EBFCD88
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io
$ sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
0e03bdcc26d7: Pull complete 
Digest: sha256:1a523af650137b8accdaed439c17d684df61ee4d74feac151b5b337bd29e7eec
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

一般ユーザでもdockerコマンドが実行できるよう、dockerグループに追加

$ sudo usermod -aG docker `whoami`
azureuser@privcr:~$ exit
azureuser@privcr:~$ docker ps -a
CONTAINER ID   IMAGE         COMMAND    CREATED          STATUS                      PORTS     NAMES
218ed82c7541   hello-world   "/hello"   55 seconds ago   Exited (0) 51 seconds ago             brave_agnesi

Docker-composeをインストール

参考; Install Docker Compose | Docker Documentation

$ sudo curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose --version
docker-compose version 1.27.4, build 40524192

HarborをHTTPSアクセス可能なように自己証明書を作成

これもほとんど公式ドキュメント通り

参考; Harbor docs | Configure HTTPS Access to Harbor

CA証明書の秘密鍵 ca.key を作成

$ mkdir cert && cd cert
$ openssl genrsa -out ca.key 4096

CA証明書 ca.crt を作成

$ openssl req -x509 -new -nodes -sha512 -days 3650 -subj "/C=JP/ST=Tokyo/L=Tokyo/O=lab/OU=lab/CN=privcr.labprivcr.com" -key ca.key -out ca.crt

このとき、Can't load /home/azureuser/.rnd into RNG とエラーになったので、以下の情報に沿って、/etc/ssl/openssl.cnfRANDFILE 行をコメントアウト

参考; Can't load ./.rnd into RNG · Issue #7754 · openssl/openssl · GitHub

サーバ証明書秘密鍵 privcr.labprivcr.com.key を作成

$ openssl genrsa -out privcr.labprivcr.com.key 4096

証明書署名要求 privcr.labprivcr.com.csr を作成

$ openssl req -sha512 -new -subj "/C=JP/ST=Tokyo/L=Tokyo/O=lab/OU=lab/CN=privcr.labprivcr.com" -key privcr.labprivcr.com.key -out privcr.labprivcr.com.csr

x509 v3 拡張属性向けの設定ファイルを生成

$ cat > v3.ext <<-EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1=privcr.labprivcr.com
DNS.2=privcr
IP.1=10.0.0.4
EOF

サーバ証明書 privcr.labprivcr.com.crt を作成

$ openssl x509 -req -sha512 -days 3650 -extfile v3.ext -CA ca.crt -CAkey ca.key -CAcreateserial -in privcr.labprivcr.com.csr -out privcr.labprivcr.com.crt

サーバ証明書秘密鍵を配置

$ sudo mkdir -p /data/cert
$ sudo cp privcr.labprivcr.com.crt /data/cert/
$ sudo cp privcr.labprivcr.com.key /data/cert/

Docker向けに privcr.labprivcr.com.crt を privcr.labprivcr.com.cert に変換し、配置

$ openssl x509 -inform PEM -in privcr.labprivcr.com.crt -out privcr.labprivcr.com.cert
$ sudo mkdir -p /etc/docker/certs.d/privcr.labprivcr.com
$ sudo cp privcr.labprivcr.com.cert /etc/docker/certs.d/privcr.labprivcr.com/
$ sudo cp privcr.labprivcr.com.key /etc/docker/certs.d/privcr.labprivcr.com/
$ sudo cp ca.crt /etc/docker/certs.d/privcr.labprivcr.com/

更新を反映させるため、dockerを再起動

$ sudo systemctl restart docker

Harborをインストール

$ wget https://github.com/goharbor/harbor/releases/download/v2.1.2/harbor-online-installer-v2.1.2.tgz
$ tar xvf harbor-online-installer-v2.1.2.tgz 
$ cd harbor
$ cp harbor.yml.tmpl harbor.yml
$ vi harbor.yml
diff harbor.yml harbor.yml.tmpl
5c5
< hostname: privcr.labprivcr.com
---
> hostname: reg.mydomain.com
17,18c17,18
<   certificate: /etc/docker/certs.d/privcr.labprivcr.com/privcr.labprivcr.com.cert
<   private_key: /etc/docker/certs.d/privcr.labprivcr.com/privcr.labprivcr.com.key
---
>   certificate: /your/certificate/path
>   private_key: /your/private/key/path

インストール

$ sudo ./install.sh
...
Creating harbor-log ... done
Creating registryctl   ... done
Creating harbor-portal ... done
Creating registry      ... done
Creating redis         ... done
Creating harbor-db     ... done
Creating harbor-core   ... done
Creating harbor-jobservice ... done
Creating nginx             ... done
✔ ----Harbor has been installed and started successfully.----

ログイン可能か確認。デフォルトのパスワードは、harbor.yml に記載のある通り、 Harbor12345

$ docker login privcr.labprivcr.com
Username: admin
Password:
WARNING! Your password will be stored unencrypted in /home/yuri/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
3.踏み台サーバにGUI環境を構築しHarborにアクセス

Web UIがあるので、踏み台サーバにGUI環境を構築し確認

UbuntuはAzureのドキュメント通り

参考; Azure の Linux VM にリモート デスクトップを使用する - Azure Virtual Machines | Microsoft Docs

$ sudo apt-get update
$ sudo apt-get install xfce4

$ sudo apt-get install xrdp
$ sudo systemctl enable xrdp

$ echo xfce4-session >~/.xsession
$ sudo systemctl restart xrdp

ログインユーザのパスワードを設定

sudo passwd azureuser
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully

Webブラウザが入っていないので、Firefoxをインストール

$ sudo apt-get install firefox

3389/TCPを踏み台サーバのNSGなどで許可 その後、RDP接続にてGUI環境が利用できます。

先に作成したCA証明書を踏み台サーバにコピーし、Firefoxにインポートします。

  • Settings > Privacy & Security > View Certificates...
  • Import...

あとはFirefoxからhttps://privcr.labprivcr.comにアクセス

f:id:hermesian:20210120220408p:plain
harbor1

4.DockerイメージをHarborにプッシュ

次にHarborにDockerイメージをプッシュしてみます。

踏み台サーバに、プライベートコンテナレジストリと同様の手順でDockerをインストール

CA証明書をインストール

$ scp yuri@privcr:/home/yuri/cert/ca.crt .
$ sudo cp ca.crt /usr/local/share/ca-certificates/
$ sudo update-ca-certificates

Harborにログインし、Dockerイメージをプッシュ libraryというプロジェクトはプリセットのものらしいです。

$ docker login privcr.labprivcr.com
Username: admin
Password:
WARNING! Your password will be stored unencrypted in /home/azureuser/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
$ docker tag hello-world:latest privcr.labprivcr.com/library/hello-world:v1
$ docker push privcr.labprivcr.com/library/hello-world:v1
The push refers to repository [privcr.labprivcr.com/library/hello-world]
9c27e219663c: Pushed
v1: digest: sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042 size: 525

Web UIからも確認できました。

f:id:hermesian:20210120220751p:plain
harbor2

AKSでネットワークパケットキャプチャを取得する

どこそこへつながらないや、つながるけどたまに切れるといった場面でネットワークパケットキャプチャを取得することがあるかと思います。 AKSの場合にどうやって取得するのかまとめてみました。

AKSノードにて取得

対象AKSノードにSSH接続し取得する方法で、一番簡単で取得可能な方法になります。 反面、解析する際には !(ip.addr == 168.63.129.16) 等、フィルタリングして目的の通信を見る必要があります。

参考; IP アドレス 168.63.129.16 とは | Microsoft Docs

  1. AKSノードにSSH接続する

AKSノードに到達可能な仮想ネットワークに踏み台サーバを用意するか、以下のヘルパーPod経由で対象AKSノードにSSH接続

Azure Kubernetes Service (AKS) クラスター ノードへの SSH 接続 - Azure Kubernetes Service | Microsoft Docs

2.ネットワークパケットキャプチャを取得する

sudo tcpdump -i any -s 0 -vvv -w `hostname`.pcap
...
対象のアクセスや操作を実行後、[Ctrl]+[C] により完了

3.対象ノードからネットワークパケットキャプチャを引き上げる

AKSノードからヘルパーPod/踏み台サーバへ scp コマンドによりコピーし、次いで、ローカル環境にコピー ヘルパーPodからローカル環境にコピーするには以下のように実施

kubectl cp $(kubectl get pod -l run=aks-ssh -o jsonpath='{.items[0].metadata.name}'):/(パケットキャプチャ結果).pcap (パケットキャプチャ結果).pcap

Podから取得

フィルタリングが楽であるためにPodからネットワークパケットキャプチャを取得できることが望ましいですが、 distrolessイメージの利用など、なるべくtcpdumpコマンドなど省いて作られたイメージを使うことが推奨事項になっています。

本命は、Ephemeral Container (kubectl debug コマンド) により対象のPodを変更させず、ネットワーク名前空間を共有する一時的なPodから取得する方法です。

Debug Running Pods | Kubernetes

上記はAlphaステージの機能のため、AKSなどのマネージドKubernetesでは対応していない状況です (GKEのアルファクラスターなら可能?)。 それに代わるものとして、ksniffというツールが現時点ではよさそうな印象があります。

GitHub - eldadru/ksniff: Kubectl plugin to ease sniffing on kubernetes pods using tcpdump and wireshark

# 1.5.0 では問題があり (https://github.com/eldadru/ksniff/issues/82)、1.4.2を利用します
$ wget https://github.com/eldadru/ksniff/releases/download/v1.4.2/ksniff.zip
$ unzip ksniff.zip
$ sudo make install
$ kubectl sniff -p (Pod名) -n (名前空間名) -o (出力先ファイル名).pcap
...
対象のアクセスや操作を実行後、[Ctrl]+[C] により完了
````

AKSノードにnode-shellでログインする

AKSにてノード (仮想マシンスケールセットインスタンス) に接続するとき、Podをデプロイしてそれを経由し、ノードにアクセスが必要。 しかし、ちょっと面倒なので、kubectl-node-shellを使ってみる。

github.com

krewと呼ばれるkubectlのプラグイン管理ツールによりインストールできる。

❯ kubectl krew index add kvaps https://github.com/kvaps/krew-index
❯ kubectl krew install kvaps/node-shell

使ってみると、実行中のコンテナも見れたりする。

❯ kubectl get nodes       
NAME                                STATUS   ROLES   AGE   VERSION
aks-nodepool1-31996622-vmss000000   Ready    agent   9h    v1.18.10
aks-nodepool1-31996622-vmss000001   Ready    agent   9h    v1.18.10
akswinp000000                       Ready    agent   9h    v1.18.10

❯ kubectl node-shell aks-nodepool1-31996622-vmss000000
spawning "nsenter-bsxuel" on "aks-nodepool1-31996622-vmss000000"
If you don't see a command prompt, try pressing enter.

root@aks-nodepool1-31996622-vmss000000:/# docker ps -a
CONTAINER ID        IMAGE                                          COMMAND                  CREATED             STATUS              PORTS               NAMES
879f57bf3305        alpine                                         "nsenter --target 1 …"   16 seconds ago      Up 16 seconds                           k8s_nsenter_nsenter-bsxuel_default_74057696-8b44-49a1-bc5f-31e2666efc12_0
...(省略)...

動作としては、alpineイメージのコンテナから、nsenterコマンドにてpidが1を指定してノードに入っている。 そのため、Windows ノードでは残念ながら動作しなかった。

❯ kubectl get pods -o wide   
NAME             READY   STATUS              RESTARTS   AGE    IP            NODE            NOMINATED NODE   READINESS GATES
nsenter-21fo6d   0/1     ContainerCreating   0          138m   10.240.0.66   akswinp000000   <none>           <none>

Windows コンテナ

Windows コンテナとは

Windows Server 2016よりサポートされたWindowsコンテナ、Linuxコンテナはまずまず不自由なく使うぐらいは触っているけど、 いまいち利用用途など見いだせず、敬遠し続けていた。

ということで、入門してみます。

2つの分離モード

Linuxと異なる点として、「プロセス分離」、「Hyper-V分離」の2つがある点が挙げられます。 前者は、Linuxコンテナと同様に、ホストのカーネルは共有する形態で、後者はホスト上に軽量の仮想マシンを挟み、その上でコンテナを動かす形態。

後者のメリットは、動作するWindowsコンテナのバージョンがホストOSのバージョンに制約されないことと、 Linuxコンテナ(いわゆる Linux Container on Windows, LCOW)もこれにより実現。

デフォルトは、プロセス分離

PS> docker info
 ...
 Default Isolation: process
 ...

環境構築

IIS をデプロイして確認してみる

使う Dockerfileはこちら。

gist41fe3ca2d129c29074aa68d939bb94e6

ポイントは、 * エスケープ文字がデフォルトではバッククォートであるため、 escape で変更 (Windowsの場合、バッククォートでディレクトリを分けるため) * LogMonitorにより、ETW形式のログを標準出力に出すように設定 * ServiceMonitorを用いて、IISをサービスとして管理

PS>docker build -t iis:v1 https://gist.githubusercontent.com/yuriwoof/41fe3ca2d129c29074aa68d939bb94e6/raw/3db06040b7acc9ad940a3d60c9ea3b4d062befb0/Dockerfile.iis
PS>docker run -d -p 8000:80 --name iis iis:v1

f:id:hermesian:20201103223157p:plain
iis

IISアクセスログも見れる

PS> docker logs -f iis
<Source>EtwEvent</Source><Time>2020-11-03T13:31:33.000Z</Time><Provider idGuid="{7E8AD27F-B271-4EA2-A783-A47BDE29143B}"/><DecodingSource>DecodingSourceXMLFile</DecodingSource><Execution ProcessID="8480" ThreadID="9152" /><Level>Information</Level><Keyword>0x8000000000000000</Keyword><EventID Qualifiers="6200">6200</EventID><EventData><EnabledFieldsFlags>2478079</EnabledFieldsFlags><date>2020-11-03</date><time>13:31:30</time><c-ip>172.16.3.4</c-ip><cs-username>-</cs-username><s-sitename>W3SVC1</s-sitename><s-computername>34c7189aaf3d</s-computername><s-ip>172.18.242.44</s-ip><cs-method>GET</cs-method><cs-uri-stem>/iisstart.png</cs-uri-stem><cs-uri-query>-</cs-uri-query><sc-status>304</sc-status><sc-win32-status>0</sc-win32-status><sc-bytes>143</sc-bytes><cs-bytes>530</cs-bytes><time-taken>2</time-taken><s-port>80</s-port><csUser-Agent>Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/86.0.4240.183+Safari/537.36</csUser-Agent><csCookie>-</csCookie><csReferer>http://localhost:8000/</csReferer><cs-version>-</cs-version><cs-host>-</cs-host><sc-substatus>0</sc-substatus><CustomFields></CustomFields></EventData>

クラスターオートスケール機能

大分昔に更新して以来すっかり更新を放置していたので、久しぶりに更新してみようと。

前回からすると、お仕事も一新 Azure を触る機会が多くなりました。 いろいろと検証するのですが、書き溜めたメモがなかなか放流できずじまいに。

今回は、Azure Kubernetes Service (AKS) でたまに聞かれることがあるクラスターオートスケール機能について書いてみます。

Azure Kubernetes Service (AKS) でのアプリケーションの需要を満たすようにクラスターを自動的にスケーリング

Kubernetes のオートスケール機能

オートスケールの対象は、PodとNode です。
Pod は、負荷に応じて、Pod 数を増減させる水平オートスケールと、Pod 数ではなく割り当てる CPU / メモリリソースを調整する垂直オートスケール機能があります。
Node の方は、クラスターオートスケール という機能で、負荷状況ではなく、 Pod が割り当てられない (Pending) になった時点で Node を追加する仕組みになります。
現時点で、 AKS でサポートしているのは、水平オートスケール機能とクラスターオートスケール機能になります。

検証

それでは検証してみます。 まずは AKS クラスターを構築します。

$ az group create --name labca --location japaneast
$ az aks create \
  --resource-group labca \
  --name labca \
  --node-count 1 \
  --node-vm-size Standard_DS2_v2 \
  --enable-vmss \
  --enable-cluster-autoscaler \
  --min-count 1 \
  --max-count 3

Standard_DS2_v2 なので、1 ノード当たり 2 vCPU (2000m) 持つことになります (実際、割り当て可能なのは、1900m)。

$ az aks get-credentials -g labca -n labca
$ kubectl get nodes
NAME                                STATUS   ROLES   AGE   VERSION
aks-nodepool1-24609861-vmss000000   Ready    agent   12m   v1.15.10

それでは、以下のようなシナリオで Node が追加されることを確認してみます。

  • 水平オートスケール (HorizontalpodAutoscaler) により、CPU 負荷が 50 % 以上を超えた場合、Pod を最大 5 つまでスケールアウトさせる
  • 対象のPodでは、絶えず負荷がかかるようにしておく

まずは水平オートスケールリソースを作成

$ cat << EOF | kubectl apply -f -
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: stress-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: stress
  minReplicas: 1
  maxReplicas: 5
  targetCPUUtilizationPercentage: 50
EOF

次いでオートスケール対象のPodを作成

$ cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: stress
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: stress
  template:
    metadata:
      labels:
        app: stress
    spec:
      containers:
      - name: stress-test
        image: busybox
        command: ["dd", "if=/dev/zero", "of=/dev/null"]
        resources:
          limits:
            cpu: 500m
          requests:
            cpu: 500m
EOF

Pod の増加を見てみます。 他の管理系のPodがあるため、2つ (cpu : 1000m)分のみしかRunningになりませんでした。

kubectl get pods
NAME                      READY   STATUS    RESTARTS   AGE
stress-864dc999dd-cpbk2   1/1     Running   0          65s
stress-864dc999dd-khfxp   1/1     Running   0          2m
stress-864dc999dd-lnggt   0/1     Pending   0          5s
stress-864dc999dd-ngbq7   0/1     Pending   0          5s

次いでクラスターオートスケールの状態を確認すると、Eventsにスケールアップのイベントが発生していることが分かります(vmss サイズを2に変更した旨)。

$ kubectl describe configmap -n kube-system cluster-autoscaler-status
...(省略)...
Events:
  Type    Reason         Age   From                Message
  ----    ------         ----  ----                -------
  Normal  ScaledUpGroup  80s   cluster-autoscaler  Scale-up: setting group aks-nodepool1-24609861-vmss size to 2
  Normal  ScaledUpGroup  80s   cluster-autoscaler  Scale-up: group aks-nodepool1-24609861-vmss size set to 2

しばらく待つと、Nodeが追加されました。

$ kubectl get nodes
NAME                                STATUS   ROLES   AGE   VERSION
aks-nodepool1-24609861-vmss000000   Ready    agent   25m   v1.15.10
aks-nodepool1-24609861-vmss000001   Ready    agent   35s   v1.15.10

それに伴い、PendingになっていたPodもデプロイされ、5つすべてRunningになります。

$ kubectl get pods
NAME                      READY   STATUS    RESTARTS   AGE
stress-864dc999dd-cpbk2   1/1     Running   0          15m
stress-864dc999dd-ffrtq   1/1     Running   0          10m
stress-864dc999dd-khfxp   1/1     Running   0          16m
stress-864dc999dd-lnggt   1/1     Running   0          14m
stress-864dc999dd-ngbq7   1/1     Running   0          14m

以上にようにアプリケーションの負荷に伴い、インフラ側でも柔軟に対応させることが可能となります。
Nodeの増減に関してより細かい設定を行うことも可能です。

クラスター オートスケーラーの設定の変更