tohokuaikiのチラシの裏

技術的ネタとか。

さくらクラウドのAPIを動かすスクリプト作った

APIからシャットダウンとかメモリ増やしたり減らしたり

したいなとういうことで。

以下のcomposer.jsonでulrichsg/getopt-phpとsakura-internet/saklientをインストールしてください。

{
    "name": "vagrant/sakura_cloug_api",
    "type": "project",
    "license": "MIT",
    "authors": [
        {
            "name": "ITOH Takashi",
            "email": ""
        }
    ],
    "require": {
        "sakura-internet/saklient": "0.0.2.11",
        "ulrichsg/getopt-php": "^3.3"
    }
}

で、このファイルを、php で叩いてもいいし、chmod 700にしても。

さくらクラウドのAPIをPHPでコマンドラインから使えるようにしたもの

使い方

とりあえず、起動・停止・リソース変更できれば僕は満足です。

トークンファイルを用意

token.iniとかで保存。中にはこんな感じで3つパラメータ設定。

zone=is1b
;; tk1a => Tokyo1
;; is1a => Ishikari1
;; is1b => Ishikari2
;; tk1v => Sandbox
token=xxxxxxxxxxxxxxxx
token_secret=***********************

コマンド実行

$ ./sakura_api.sh -h

でだいたいわかるけど。

起動

$ ./sakura_api.sh boot -s api_test_server -t token.ini

-sオプションで自分のさくらクラウドのサーバー名を指定、-t オプションでさっき作ったTokenファイルを指定。

状態確認

$ ./sakura_api.sh status -s api_test_server -t token.ini

停止

$ ./sakura_api.sh stop -s api_test_server -t token.ini

プランを変更

CPU1コア、メモリ2Gに変更

$ ./sakura_api.sh plan -s api_test_server -t token.ini -m 2 -c 1

さくらのクラウドで共有セグメントにつながれた2つのサーバーでsshする

OSはdebian10

共有セグメントから2つぶら下げる感じでサーバーを立てた。1つは本番、1つはバックアップ兼緊急時用。

f:id:tohokuaiki:20200406213101p:plain

で、バックアップ用から本番サーバーにsshしようとしたらつながらない…No route to host…

ん~。ネットワークのことよく知らないからこの辺り「何でつながらないんだ?」となってしまった。

IPアドレスが第2セグメントまで同じなので、サブネットマスクを255.255.0.0にしたらいけるのか?と思いきやダメ。

ローカルでつなぐ

というわけで、サーバーにそれぞれNICを1枚ずつ追加し、追加したスイッチでローカルでつないでみた。こんな感じ。

f:id:tohokuaiki:20200406213618p:plain

で、ネットワークIPアドレスを設定する。

本番サーバー /etc/network/interfaces に下記を追加

auto ens4
iface ens4 inet static
        address 192.168.0.10
        netmask 255.255.255.0

全部でこんな感じ。

# more /etc/network/interfaces
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
allow-hotplug ens3
auto ens3
iface ens3 inet static
        address 153.127.xxx.xxx
        gateway 153.127.xxx.1
        # dns-* options are implemented by the resolvconf package, if installed
        # dns-nameservers 133.242.0.3 133.242.0.4
        dns-nameservers 210.188.224.10 210.188.224.11
        dns-search anytimefitness.co.jp

iface ens3 inet6 static
        address 2401:2500:102:3017:153:126:162:197
        netmask 64
        gateway fe80::1
        dns-nameservers 2401:2500::1

auto ens4
iface ens4 inet static
        address 192.168.0.10
        netmask 255.255.255.0

バックアップ用にも同様にIPアドレスだけ変えて追加。

これで通信できるようになった。

iptablesの設定を忘れずに

#########
#local network
#########
iptables -A INPUT -s 192.168.0.0/16 -j ACCEPT
iptables -A OUTPUT -s 192.168.0.0/16 -j ACCEPT

ってやっておく。

さくらのクラウドディスクサイズを縮小する。

前提と経緯

  1. さくらのVPS8G→VPS32Gとサービス成長に合わせてマイグレーションした
  2. 128Gまで使えるクラウドに移行したい。
  3. でもVPS32Gの1.6Tなんて使いっこないのでパーティションの拡張はずっとしてない
  4. ただ、HDDとしては1.6Tなんで節約のために500Gに移行させたい(それでもまだ200G以上余裕ある)

というのがある。

というのを踏まえてホントにできるんか?というメモ。(ネタバレうすると、できなくて結局最後は強引な感じでddrescue使った) こちらの記事を参考に。

ディスクを作成して、サーバーに接続

こんな感じ。 f:id:tohokuaiki:20200404222652p:plain

下に付いているのが移行する先のディスク

ディスクのパーティションを作る。

#cfdisk /dev/vdb

でこんな感じ

                                                                   Disk: /dev/vdb
                                                Size: 500 GiB, 536870912000 bytes, 1048576000 sectors
                                                         Label: dos, identifier: 0x874ecaad

    Device                Boot                       Start                End           Sectors          Size         Id Type
    /dev/vdb1             *                           2048          838862847         838860800          400G         83 Linux
    /dev/vdb2                                    838862848          872417279          33554432           16G          5 Extended
    mqFree space                                 838864896          872417279          33552384           16G
>>  /dev/vdb3                                    872417280         1006635007         134217728           64G         82 Linux swap / Solaris
    Free space                                  1006635008         1048575999          41940992           20G

確認

# fdisk -l /dev/vdb
Disk /dev/vdb: 500 GiB, 536870912000 bytes, 1048576000 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x874ecaad

Device     Boot     Start        End   Sectors  Size Id Type
/dev/vdb1  *         2048  838862847 838860800  400G 83 Linux
/dev/vdb2       838862848  872417279  33554432   16G  5 Extended
/dev/vdb3       872417280 1006635007 134217728   64G 82 Linux swap / Solaris

はい。

# lsblk
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sr0     11:0    1 1024M  0 rom
vda    254:0    0    1T  0 disk
tqvda1 254:1    0  384G  0 part /
tqvda2 254:2    0    1K  0 part
mqvda5 254:5    0   16G  0 part [SWAP]
vdb    254:16   0  500G  0 disk
tqvdb1 254:17   0  400G  0 part
tqvdb2 254:18   0    1K  0 part
mqvdb3 254:19   0   64G  0 part

フォーマットする。

# mkfs.ext4 /dev/vdb1
mke2fs 1.43.4 (31-Jan-2017)
Creating filesystem with 104857600 4k blocks and 26214400 inodes
Filesystem UUID: c1080d22-de41-4042-971c-d0daaed38694
Superblock backups stored on blocks:
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
        4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968,
        102400000

Allocating group tables: done
Writing inode tables: done
Creating journal (262144 blocks): done
Writing superblocks and filesystem accounting information: done

…で、データをコピー…と、ここまできて動いているOSの上でコピーしたらいかんやん…ということに気付く。

ということで作業用のOSが載ったディスクを追加

とりあえず、同じdebianでディスクを作成する。20Gもいらんのになぁ…

で、こんな感じにサーバーに取り付ける。 f:id:tohokuaiki:20200404225612p:plain

上から、

  1. 今回作ったテンポラリの作業用debian
  2. 現在使っているディスク
  3. 移行先のディスク

これで起動するとテンポラリ作業用のdebianが起動した。

# lsblk
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sr0     11:0    1 1024M  0 rom
vda    254:0    0   20G  0 disk
|-vda1 254:1    0    1M  0 part
|-vda2 254:2    0    4G  0 part [SWAP]
`-vda3 254:3    0   16G  0 part /
vdb    254:16   0    1T  0 disk
|-vdb1 254:17   0  384G  0 part
|-vdb2 254:18   0    1K  0 part
`-vdb5 254:21   0   16G  0 part
vdc    254:32   0  500G  0 disk
|-vdc1 254:33   0  400G  0 part
|-vdc2 254:34   0    1K  0 part
`-vdc3 254:35   0   64G  0 part

となって、なるほど。

ということで、マウントする。

root@debian:~# mkdir /disk-source /disk-target
root@debian:~# mount /dev/vdb1 /disk-source
root@debian:~# mount /dev/vdc1 /disk-target

これで/disk-sourceディレクトリの内容を全部コピーする。なるだけファイルの属性値も含めてのオプションのpを使う。

root@debian:~# cp -frp /disk-source/* /disk-target/

このあたり、クラウドだと失敗しても最悪アーカイブからまたディスク作ればいいやっていう安心感がいいよね。

で、あとは参考記事の通り

アンマウントしてファイルシステムのチェック

root@debian:~# umount /disk-source
root@debian:~# umount /disk-target
root@debian:~# e2fsck -f /dev/vdc1

UUIDを合わせる

# blkid
/dev/vda1: PARTUUID="e79a082c-5910-4522-bf37-c7343384199d"
/dev/vda2: UUID="147cd78f-e402-489d-a643-b48e7ac5d14d" TYPE="swap" PARTUUID="7efbdfc3-89bc-4812-a6e2-f3ac8fc8f177"
/dev/vda3: UUID="ab071864-a09a-45fb-9d64-64b86994c5fa" TYPE="ext4" PARTUUID="97b8211b-0659-459b-9056-5a02466726f4"
/dev/vdb1: UUID="248ebabe-9352-4f7f-a4d9-1d5447620931" TYPE="ext4" PARTUUID="5cc2985a-01"
/dev/vdb5: UUID="03889948-427a-41dd-82cc-7e000c98255e" TYPE="swap" PARTUUID="5cc2985a-05"
/dev/vdc1: UUID="c1080d22-de41-4042-971c-d0daaed38694" TYPE="ext4" PARTUUID="874ecaad-01"
/dev/vdc3: PARTUUID="874ecaad-03"

/dev/vdb1 と /dev/vdc1を同じに。

root@debian:~# tune2fs -U 248ebabe-9352-4f7f-a4d9-1d5447620931 /dev/vdc1

忘れてた。swapを作る。

あれ?blkidで/dev/vdc3がswapになってないじゃん…

root@debian:~# mkswap /dev/vdc3
root@debian:~# blkid|grep vdc3
/dev/vdc3: UUID="d0a8a656-e56b-4b1c-8ac9-98347a30b2a2" TYPE="swap" PARTUUID="874ecaad-03"

…が、起動しない…

んー。この辺り、Linuxの根本のところをよくわかってないからな…まじめにやらないとなー。といってもとりあえずですませたいなー。…

ブートローダーをインストールしないと

/etc/fstabを見てると

# / was on /dev/vda1 during installation

とか

# swap was on /dev/vda5 during installation

とかある。んー。

諦めてddrescueを使うことに

www.itmedia.co.jp

でさくっと。 作業用のdebian

root@debian:~# apt install gddrescue

で、強制上書き。/dev/vdbが古い方で、/dev/vdcにコピーする。

root@debian:~# ddrescue -v --force /dev/vdb /dev/vdc

そもそもなんでこれが上手くいくかというと…、古い方のHDDは1Tだけど、パーティションとしては400Gしか切ってないのでなんか上手くいかんかな?という…

当然最後にはno space to leftっていうようなエラーが出たけど…コピー完了。blkidするとUUID・PARTUUIDまで一緒になってコピーされてる。

# blkid
/dev/vda1: PARTUUID="e79a082c-5910-4522-bf37-c7343384199d"
/dev/vda2: UUID="147cd78f-e402-489d-a643-b48e7ac5d14d" TYPE="swap" PARTUUID="7efbdfc3-89bc-4812-a6e2-f3ac8fc8f177"
/dev/vda3: UUID="ab071864-a09a-45fb-9d64-64b86994c5fa" TYPE="ext4" PARTUUID="97b8211b-0659-459b-9056-5a02466726f4"
/dev/vdb1: UUID="248ebabe-9352-4f7f-a4d9-1d5447620931" TYPE="ext4" PARTUUID="5cc2985a-01"
/dev/vdb5: UUID="03889948-427a-41dd-82cc-7e000c98255e" TYPE="swap" PARTUUID="5cc2985a-05"
/dev/vdc1: UUID="248ebabe-9352-4f7f-a4d9-1d5447620931" TYPE="ext4" PARTUUID="5cc2985a-01"
/dev/vdc5: UUID="03889948-427a-41dd-82cc-7e000c98255e" TYPE="swap" PARTUUID="5cc2985a-05"

で、シャットダウン→ディスク外し→起動

…おぉ、起動した。

PHPの関数内で自己再帰呼び出し

できるかな?と思ってテスト…

<?php
function r($count)
{
    echo $count."\n";
    if ($count < 10) {
        r(++$count);
    }
}
r(1);

1
2
3
4
5
6
7
8
9
10

でも、関数名を変えると再帰呼び出ししてるところも変えないといけない。

__FUNCTION__を使う

関数内では、__FUNCTION__が関数名を示すので

<?php
function r($count)
{
    echo $count."\n";
    if ($count < 10) {
        __FUNCTION__(++$count);
    }
}

ってやった…Parse Error…ですよねー。

一旦変数にする。

<?php
function r($count)
{
    $f_name = __FUNCTION__;
    echo $count."\n";
    if ($count < 10) {
        $f_name(++$count);
    }
}

これはうまくいった。だけど…だけどですよねー。JavaScriptならarguments.callee使えるのになー。

(function(c){ 
    console.log(c++);
     if (c<10) {
        arguments.callee(c);
    }
})(1)

PHPのClosureは変数に入れてるしなー。ダメっぽいな。

MovableTypeの$__value__に気をつける。

特殊変数のvalue

ループで使えるんだけど、

<mt:SetHashVar name="month">
<mt:SetVar name="Jan" value="January">
<mt:SetVar name="Feb" value="February">
</mt:SetHashVar>

<mt:Loop name="month" sort_by="value">
  <li><mt:Var name="__key__">: <mt:Var name="__value__"></li>
</mt:Loop>

https://www.movabletype.jp/documentation/appendices/tags/loop.html

なんと、MTContentFieldでも使えるのであった…

<mt:Contents content_type="イベント・セミナー" limit="1">
    <mt:ContentField content_field="開催日時"><mt:ContentFieldValue></mt:ContentField>
</mt:Contents>

という感じだけど、

<mt:Contents content_type="イベント・セミナー" limit="1">
    <mt:ContentField content_field="開催日時"><Var name="__value__"></mt:ContentField>
</mt:Contents>

でもいけてしまうのであった…。 https://www.movabletype.jp/documentation/appendices/tags/contentfield.html

Loopの中で_value_使ってた自分、_value_がMTContentFieldで上書きされていることに気づかず無為な時間を過ごしてしまった…

そして、普通に_value_と書くと、はてブではvalueになってしまうのか…_\_value_\_と書かねばならないのだな。