システム運用担当者から見た自動化について

ITの仕事をしていると、誰しも自動化にかかわったことがあると思います。スクリプトを書いてデータを生成したり、ログを集めてコピーしたりなど、簡単なことからシステムの構築、アプリケーションのデプロイなど今では自動化できないものが少なくなってきているような感じもします。

同じIT業界でも職種によっても自動化の内容は異なってきます。開発者ならビルドの自動化、QAエンジニアならテストの自動化など職種によっても重要度も異なるでしょう。

ここでは、運用担当者の目線で自動化をどのように行っていくか考えてみたいと思います。

# なぜ自動化するか
これは、立場によって理由も異なると思います。例えば経営陣やプロジェクトマネージャーなどの立場なら、自動化することによって業務の効率化向上や、退職や予算カットなどに対してリスクヘッジが期待もできると思います。

運用担当者の立場でいうと、個人的には同じことを2回もしたくない、良い意味で手動でコマンドなんかを打つのは面倒で、できれば一回行った作業は次以降は自動的に行えるようにしておきたいものです。

例えば、システムのログを指定のストーレジに収集して一定期間保管する必要があるとします。ログの量にもよりますが、手作業の場合は毎日対象のシステムにログインして、ログをストーレジにコピー、さらに一定期間が過ぎた古いログは削除する必要があります。
手動でももちろんできますが、これは基本的に同じ手順の作業を繰り返し行って期待できるアウトプットは（新しいログがコピーされ古いログが削除される）毎回同じです。

簡単な例えですが、これを毎日手作業で行うのは時間の無駄です。それに費やす時間があったら、他のクリエイティブなタスクに時間を費やすべきです。この例だと、簡単なスクリプトを書いて、スクリプトが失敗した時だけアラートを出すようにしていれば、ひょっとしたらそのシステムを運用している間に二度と見る必要がなくなるかもしれません。

無駄な時間を削減できるというのもありますが、担当者としてはやっぱり面倒な手作業はできるだけ行いたくありません。この”面倒な手作業”と言う感覚をもって仕事な当たれば、それをなくすために可能なものは自動化したくなります。

# 何を自動化するか
自分が担当しているプロジェクトでは、デファルトは自動化で技術的に無理なものだけ手動で行うようにしています。セットアップして二度と触る必要がないようなものでない限り、できるだけ自動化することにしています。クラウドリソースのデプロイ、システムの構築、アプリケーションのデプロイ、モニタリングの設定、自動復旧など運用上必要な項目はほぼ自動化されています。

### CI/CD用のクラウドリソースのデプロイ
CI/CDをセットアップすれば、実際のシステムのクラウドリソース自体はパイプラインを通してデプロイできるので、先ずはCI/CDをセットアップするためにそのリソースをデプロイします。

クラウドリソース、例えばAzureのリソースグループ、AKSやOpenStackでVMなどを一番最初にセットアップする場合は、少なからず手動でコマンドを打つ必要があります。例えばTerraformを使用すると、リソースを作成して消去することがコマンド一つでできるようになります。


**Azure**

```terraform
resource "azurerm_resource_group" "myresourcegroup" {
    name     = "myresourcegroup"
    location = var.location
}

resource "azurerm_kubernetes_cluster" "myaks" {
    name                = "myaks"
    resource_group_name = azurerm_resource_group.myresourcegroup.name
    location            = var.location
    dns_prefix          = local.cluster_name
    kubernetes_version  = local.k8s_version
.
.
```
**Openstack**

```terraform
resource "openstack_compute_instance_v2" "myvm" {
  count           = var.myvm_count
  name            = "myvm1"
  region          = var.region
  image_id        = var.vm_image
  flavor_id       = var.vm_flavor
  key_pair        = var.key_pair
.
.
```

Terraformをデプロイするリソースの用途に合わせて分割して実行できるようにすると、一番最初の基本のリソースをセットアップするときだけ手動でTerraformを実行し、それ以外のリソース（例えば、KubernetesのDeployment,DNSなど）のデプロイはCI/CDを使ってTerraformの実行を自動化することができます。

### CI/CDのセットアップ
初期のTerraformでKubernetesやVMをセットアップできれば、それ以降のシステムはCI/CDを使って自動化を目指します。そのためにはCI/CDをセットアップする必要があります。

**Jenkinsのセットアップ**

https://github.com/jenkinsci/helm-charts/blob/main/charts/jenkins/README.md

こちらのHelm Chartをつかって、JenkinsをHelmでセットアップできます。

Jenkins Configuration as Codeを使ってJenkinsを設定すると、Jenkinsのパイプラインも合わせて設定できますし、基本的にJenkinsの設定をすべてコードで行えUI上で手動で設定する必要がありません。

https://www.jenkins.io/projects/jcasc/

```yaml
controller:
  JCasC:
    configScripts:
      welcome-message: |
        jenkins:
          systemMessage: My CICD system

        jobs:
          - script: >
              folder('DEVQA') {
                  displayName('Dev and QA')
                  description('Dev and QA deployment')
                  authorization {
                     permissions('my_devteam', [
                         'hudson.model.Item.Build',
                         'hudson.model.Item.Cancel',
                         'hudson.model.Item.Read'
                     ])
                  }
              }        
          - script: >
              pipelineJob('My pipeline') {
                  description("Deploy Application")
                  parameters {
                    choiceParam('TARGET', ['dev', 'qa'], 'Target environment')
                  }
```

手動でコマンドを実行して何かをセットアップするのは以上で終わりです。これ以降は基本的に自動化のためのコードを書いて、それをリポジトリでバージョン管理をして、リポジトリを元にすべての変更をCI/CDで実行するようになります。

### Jenkinsエージェント用のイメージ
Jenkinsのパイプライン上で利用するイメージをビルドする必要があります。これ以降のパイプラインで必要なコンポーネントをいくつかのイメージに分けてビルドすると、イメージを小さくすることができます。
必要なコンポーネントは対象システムによりますが、`kubectl`、`kubelogin`、`az`、`terraform`、`helm`、`curl`、`wget`、`git`、`maven`などパイプライン上で必要な機能をイメージに追加します。

これらのイメージ自体のビルドもパイプラインで自動化します。

```groovy
stage ('Build Maven Image') {
    steps {
        script {
            dir("/jenkins") {
                git (
                    credentialsId: 'git-service-account',
                    url: "${BUILDREPO}",
                    branch: 'primary'
                )
                container(name: 'kaniko', shell: '/busybox/sh') {
                    sh '''#!/busybox/sh
                    /kaniko/executor -f /jenkins/maven/Dockerfile -c /jenkins/maven/ --destination=myregistry.azurecr.io/myapp-maven:latest
                    '''   
                }					

            }
        } 
    }
} 

```

### システムの構築
実際のシステムを構築するためのクラウドリソースのデプロイは、パイプラインを通してTerraformでデプロイできます。

```groovy
stage ('Run Terraform') {
    steps {
        script {
			container('jenkinsagent'){
				sh '''
					set +x 
					az login --service-principal --username ${SP_CLIENT_ID} --password ${SP_CLIENT_PW} --tenant ${TENANT_ID}
					export TF_VAR_client_secret=${SP_CLIENT_PW}
					export ARM_CLIENT_ID="${SP_CLIENT_ID}"
					export ARM_CLIENT_SECRET="${SP_CLIENT_PW}"
					export ARM_SUBSCRIPTION_ID="*****-****-****-*****"
					export ARM_TENANT_ID="${TENANT_ID}"

					echo "Run Terraform"
					terraform ${ACTION} -auto-approve
				'''	
			}
        } 
    }
} 

```

この様にパイプラインを設定すると、あとはTerraformをセットアップする対象のシステムリソースごとに分けて、それぞれの管理を自動化できます。リソースのビルドを自動化できるので、削除も同じようにパイプラインを使って行うこともできますし、何か問題があった場合に再構築もパイプラインを実行するだけで行えます。


### アプリケーションのデプロイ、モニタリングの設定、自動復旧

システムが構築されると、その後はアプリケーションのビルド、デプロイ、テストなどを自動化する必要があります。また、Kubernetesを使用する場合はコンテナイメージのビルド、レジストリーへのアップロードなども同じくパイプラインで自動化をすることができます。

また、システムを運用し始めると監視ツールを使ってシステムやアプリケーションの監視をする必要があります。規模が大きくなってくると監視項目の設定なども膨大になり、それをすべて手作業で行うのはかなりの手間がかかります。システムの運用体制にもよりますが、クラウドでサーバなどのリソースを頻繁に入れ替えたりするようなシステムや、デプロイ時にアラートをOn/Offする必要があるような場合、APIなどで自動的に監視項目、アラートの設定などをパイプラインからできるようにしておくと非常に便利です。

監視ツールを使ってシステムを監視するなら、障害発生時にそれを自動的にパイプラインで対象システムをチェックして自動復旧できるようにすると、運用担当者の手間も大幅に省かれます。監視ツールと自動復旧については以前別の記事を書きましたのでそれをご覧ください。

https://qiita.com/dg4101/items/0aeae61a16b979f00f80

これら以外にも、バックアップ、リストア、障害発生時に再構築する必要のあるリソース、ログの管理、TLS証明書の期限確認と更新、ユーザー権限の管理など、運用担当者が毎日ではないが年か月に何度か行う程度のタスクなども自動化しておくとタスクによっては以降全く何もする必要が無くなることもあります。

# 自動化のメリットとデメリット

### メリット
* 自動化を行うと、基本的には同じ作業を繰り返し手作業で行う必要がありません。自動化のテストで動作確認をしっかり行うと次回以降は、問題なく対象となっているタスクを実行してくれます。手作業で行うとちょっとしたことでエラーを出して重大な障害につながる可能性もあります。
* 自動化しているので、スケジュールを組んで、夜中や週末などスステムの負荷が少ない時間などに特定のタスクを実行できます。
* JenkinsのパイプラインはJenkins Fileを使って設定出来うるので、それをGitでバージョン管理を行うと自動化のタスクを共有でき自動化のドキュメントとしても使用できます。プロジェクトのメンバーがJenkins Fileを読めるようにしておくと、自動化でどのようなタスクを行っているかなどメンバー全員が確認できて、いちいち説明をする必要が無くなります。
* 自動復旧を設定すると、アラートが出る度にシステムの確認作業をする必要が無くなり、パイプラインで自動的に確認をして復旧をすることができます。自動復旧に失敗した時だアラートを出るようにしておくと、夜中や週末に緊急の対応をする必要も減ると思われます。
* システム構築の工程をすべて自動化できると、重大障害が発生し再構築が必要になった場合にそれらの自動化されたタスク、パイプラインを実行するだけで再構築できるので、復旧に必要な時間の大幅削減が見込まれます。
* システム構築の手順が基本的にはコードで管理できているので、担当者が変わっても引き継ぎが行いやすく、基本的な部分は担当者の経験や勘などに頼る必要がなく運用ができるようになります。 

### デメリット
* 担当者のパイプラインのコードを書く技術やセンスによって異なるので、あらかじめルールを作っておかないとチーム内で完成度の違うパイプラインが作られる可能性があります。
* 内容によっては、手作業で行った方が早い場合もありオーバーエンジニアリングとなる場合もあります。優先度や重要性を見極め、何を自動化するか検証する必要があります。
* 自動化されたタスクを実用化する前に、テストに多くの時間を割く必要があります。自動化なので間違った設定で行うと、間違った結果が出続けることになります。
* 自動化に慣れてくると、運用のかなり詳細な所まで自動化ができることが分かってくると思います。これをどの程度の完成度で自動化を行うかを優先度を考慮して決めないと、先ほどのようにオーバーエンジニアリングとなる場合があります。

# 自動化はエンジニアの職を奪うのか？
自動化を進めると、以前はエンジニアがリクエストされて対応していたタスクの多くが自動的に勝手に行えるようになりリクエストそのものが少なくなってくると思います。そうすると、”自動化はエンジニアの職を奪うのか”と言った疑問も出てきます。
おそらく一部の初期レベルの対応をするような作業は自動化によってなくなっていくと思いますが、自動化がエンジニアの職を奪うまではいかないと思います。

いくら自動化してもシステムの需要や要件は常に変化し続けますし、システムの状態も負荷やユーザー数などで変わり続けます。エンジニアは、それれらの変化に対応して常にシステムを改善していく必要があります。変化を分析してどのように対処するかは、エンジニアの経験、リソースの関係、予算の都合などで変わってくるのでそれらを自動化するのは難しく、エンジニアが本来の能力を発揮するところでもあります。
また自動化されたタスクが全くバグがなく実行できるかというと、アプリケーションと同じでバグがゼロになるとこはないでしょう。それら自動化されたタスクのメンテナンスなどもエンジニアの重要な仕事です。

ただ、自動化する前に比べて初期レベルのタスクに時間を割く必要はなく、より高度でクリエイティブなタスクにエンジニアが時間をさけるようになると思います。それによって、システムの成熟度も上がって安定した運用へとつながるでしょう。

# 自動化できないもの
運用担当者の目線で見ると、普段行うタスクの中で自動化できないものはあまりありません。もちろんシステムによっては設定などをUIでしかできないももあったりして全てではないですが、コマンドラインで行えるタスク、ファイルやデータベースで管理している設定などは全て自動化できるはずです。

普段から自動化することを前提にしていると、何かのタスクをした時に次回以降どうやって自動で実行できるかを考えながらタスクを進められ、終了時点では自動化のコンセプトも出来上がったりします。

# まとめ
自動化について運用担当者目線からどのように実装して、そのメリットやデメリットを考えてみました。今でもそうですが、これからシステムの運用はクラウドで行うのが前提となってくると思います。自動化は、クラウド上でシステム運用を効率的に行うためには必要条件と言っても過言ではありません。

この記事ではTerraform、Jenkinsを使った例を挙げましたがそれ以外にも多くの方法があります。会社、プロジェクト単位でスタンダートとなる自動化のテクノロジーを決めて、それらのコードをGitなどで共有できるようにすれば相乗効果もあってより効率的に自動化を進められると思います。

”面倒な手作業”をなくすために、自動化を進めてみませんか？