お前らのCFデプロイはダサい


これはよくある煽り系釣りタイトルみたいなものです。怒らないでください。
怒った方はごめんなさい。
（※ この記事は [SAP Advent Calendar 2019](https://adventar.org/calendars/3908) の12月21日分の記事としても執筆しています）

**2020年2月追記**
本記事をさらにアップグレードした、[やはりお前らのCFデプロイはダサい](https://qiita.com/tnmrknm/items/19ad7195259fbf083a2b)を公開しました。

##ダサいデプロイとは - パラダイムへの反骨

わたくし、お片づけが大好きな"片づけコンサルタント"でございます。
特に、心ときめくようなシンプル、かつモダンでイケてるシステムアーキテクチャを作ることに興奮を隠しきれません。

そんな片づけコンサルタントがSAP Cloud PlatformのCloud Foundry(CF)での開発で許せないことの一つに、MTAアプリケーションの手動ビルド、手動デプロイというプロセスがあります。


イチイチBuildボタンをポチポチしては、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277725/f0b514e7-b646-a588-a488-cf335b66ce08.png)
完了までシバシバ待ち、
完了したらデプロイボタンを押してまたムクムク待ち…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277725/212edf52-02df-7bd1-f3b3-68d324efeeae.png)

時は令和です。
みなさん、こんな**ダサい**ことをしている場合ではございません。

今回はこんな、心ときめかない手動ビルド、手動デプロイというプロセスをブチコリと排除して、かわいく自動でビルド、デプロイを行ってくれるアーキテクチャを作ってスッキリしたDevOps※実行環境の構築を目指しましょう。

※DevOpsについては[こちら](https://hackernoon.com/the-2018-devops-roadmap-31588d8670cb)

それでは早速方法を見てみましょう。




## 理想的なアーキテクチャ -ユートピア



本来、SAP Cloud PlatformのCFで作られるべきDevOpsを実現するアーキテクチャは、だいたいこんな感じであるとわたくしは思っております。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277725/89f58fcb-737c-d9ff-f79b-603a2a03a6c2.png)

あぁ・・・・//

失礼、取り乱してしまいました。
上記で何を行っているかといいますと、ざっくり以下のような感じです。

- ローカル、もしくはNeo環境のWebIDEから、CF環境に置いたGitlabコンテナに対してMTAプロジェクトのプッシュ
- GitlabへのプッシュをトリガーにしてJenkinsコンテナ内でMTAプロジェクトをビルド
- MTAビルド時に、共通ライブラリをnexusコンテナから取得する
- JenkinsからCFランタイム環境へMTAアプリケーションをデプロイ
- JenkinsからGitlabへ.mtarファイルをプッシュし、.mtarファイルをCTS+にて各CF環境へ配備

あぁ、なんと美しいのでしょう。
これにて手動のビルド、デプロイや移送などというダサい作業からは解脱できるのです。

**ですが**
こちらは2019年現在実現できません。。
何故なら、現在SAP Cloud PlatformのCF環境にはストレージサービス(NFS)が存在しないのです！
そのため、JenkinsやGitlabなどのコンテナを立てることはできても、開発オブジェクトやユーザ情報、コンフィグなどを永続化させることができず、コンテナの再起動がかかる度に消えてしまうのです。。

そのことを知った時、私は途方に暮れました。
悔しくて夜も眠れず、朝も起きられませんでした。


**しかし！**
そんな私を救ってくれたのが**Azure DevOps**だったのです！！


**2020年2月追記**
Cloud Foundry環境にコンテナを立ててDevOpsを実現することがベストプラクティスだと悦に入っていましたが、現時点ではAzure DevOpsの方が断然楽にDevOpsを実現できて良いです。
完全に寝返ってしまいました。すいません。


## Azure DevOpsの登場 -メシアの出現

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277725/b0b8efeb-2657-25b6-823b-2f86d6d104cb.png)

このAzure DevOpsとは、Microsoft Azureの中の1サービスであり、GitやJenkinsのようなCI/CDツールとしての役割を包含したものです。
今回はこの、美しいサービスを利用してDevOpsを実現していくことにします！


## 前提プロジェクト -MTA

今回は、workshop1128というMTAプロジェクトの自動ビルド、自動デプロイを行っていきます。
その構成はこちらです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277725/adb1dce8-6d58-c59c-7e71-3ea8cff080dc.png)

MTAプロジェクトの下にJavaモジュール、UI5モジュール、hdiモジュールを作成した形です。
もう少し詳しく見るためにmta.yamlを添えておきます。

```yaml:mta.yaml
ID: workshop1128
_schema-version: '2.1'
parameters:
  deploy_mode: html5-repo
version: 0.0.1
modules:
  - name: workshop1128_appRouter
    type: approuter.nodejs
    path: workshop1128_appRouter
    parameters:
      disk-quota: 256M
      memory: 256M
    requires:
      - name: workshop1128_html5_repo_runtime
      - name: uaa_workshop1128
  - name: workshop1128_ui_deployer
    type: com.sap.html5.application-content
    path: workshop1128_ui_deployer
    requires:
      - name: workshop1128_html5_repo_host
    build-parameters:
      requires:
        - name: workshop1128ui5
          artifacts:
            - './*'
          target-path: resources/workshop1128ui5
  - name: hdi1128
    type: hdb
    path: hdi1128
    requires:
      - name: hdi_hdi1128
  - name: workshop1128java
    type: java
    path: workshop1128java
    parameters:
      memory: 1024M
    provides:
      - name: workshop1128java_api
        properties:
          url: '${default-url}'
    requires:
      - name: ls_tokyo-connectivity
      - name: dest_workshop1128
      - name: uaa_workshop1128
      - name: hdi_hdi1128
        properties:
          JBP_CONFIG_RESOURCE_CONFIGURATION: '[tomcat/webapps/ROOT/META-INF/context.xml: {"service_name_for_DefaultDB" : "~{hdi-container-name}"}]'
  - name: workshop1128ui5
    type: html5
    path: workshop1128ui5
    build-parameters:
      builder: grunt
      supported-platforms: []
      build-result: dist
resources:
  - name: workshop1128_html5_repo_runtime
    parameters:
      service-plan: app-runtime
      service: html5-apps-repo
    type: org.cloudfoundry.managed-service
  - name: workshop1128_html5_repo_host
    parameters:
      service-plan: app-host
      service: html5-apps-repo
    type: org.cloudfoundry.managed-service
  - name: hdi_hdi1128
    parameters:
      config:
        schema: sawayaka
    properties:
      hdi-container-name: '${service-name}'
    type: com.sap.xs.hdi-container
  - name: uaa_workshop1128
    parameters:
      path: ./xs-security.json
      service-plan: application
      service: xsuaa
    type: org.cloudfoundry.managed-service
  - name: dest_workshop1128
    parameters:
      service-plan: lite
      service: destination
    type: org.cloudfoundry.managed-service
  - name: ls_tokyo-connectivity
    parameters:
      service-plan: lite
      service: connectivity
    type: org.cloudfoundry.existing-service
```


## Azure DevOpsをさわってみよう -初体験

ということで早速上記で用意したMTAプロジェクトをAzure DevOpsでブチコリと料理する方法をご紹介しましょう。

### Gitリポジトリの利用

まずはAzure DevOpsのGitサービスであるReposから新しいRepositoryを作成していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277725/611b22f8-399b-f4dd-f998-d6565d1c0842.png)

元々GitにあるオブジェクトをCloneしてくることが出来るので、既にSAP Cloud Platformで利用しているGitリポジトリを入力すればOKです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277725/25edf4d4-a40d-45dd-5cf6-c2ddcdf0b096.png)

そうするとこのような形で先ほどのworkshop1128プロジェクトをAzure DevOps上に持ってくることができます。

もし継続してAzure DevOpsを使う場合は、こちらのリポジトリをリモートリポジトリとして使用すれば、後述するCI/CDパイプラインをGitへのプッシュをトリガにして実行することも可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277725/a7d8558c-295f-c5d5-f42d-7e618c20c987.png)


### CI/CDツールとしてのパイプライン構築

メインとなる自動ビルド、自動デプロイを実行する、パイプラインの構築を行っていきます。
まずはPipelinesを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277725/f636dc1b-7b86-8b46-9719-d5a2157a2134.png)


New build pipelineを選択して新規パイプラインを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277725/ce3f7a76-f08a-2843-d31e-0946fb718eea.png)

パイプラインで扱うプロジェクトを、先ほどのAzure DevOpsのGitから持ってきます。
他にもGithubやBitbucketがあり、SAP Cloud PlatformのGitサービスも選択できるように見えていますが、パイプラインを自由に定義できなくなってしまうので、Azure DevOpsのGitを使うのが良いかと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277725/5e9952f9-2b10-9b1c-4f3f-fe3502859188.png)

先ほど移したworkshop1128プロジェクトを選択する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277725/b29952b3-329f-cb2a-f178-5fef581ae128.png)

ここからパイプラインの定義をしていきます。
様々な言語でビルド、デプロイを行うためのテンプレートyamlが用意されていますが、MTAのテンプレートは用意されていないので、今回はNode.jsのテンプレートを暫定的に選択して中身を入れ替えることにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277725/df3fcdd3-885b-3514-a403-9194abbb03b3.png)

このNode.jsのために書かれたazure-pipeline.yamlを以下のように書き換えてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277725/1661075a-8505-f62e-690f-07275629244c.png)





```yaml:azure-pipelines.yml
# Starter pipeline

name: sawayaka-mta-project
resources:
  containers:
  - container: mta
    image: 'ppiper/mta-archive-builder:latest'
    options: --user 0:0
  - container: cfcli
    image: 'ppiper/cf-cli'
    options: --user 0:0 --privileged
  - container: node
    image: 'geekykaran/headless-chrome-node-docker:latest'
    options: --privileged


trigger:
- master


stages:
- stage: build
  displayName: Build MTA for SAP Cloud Platform
  jobs:
    - job: build
      pool:
        vmImage: 'ubuntu-latest'
      container: mta
      steps:
        - bash: 'mtaBuild --build-target CF --mtar MySampleApp.mtar build'
        - publish: $(System.DefaultWorkingDirectory)/.
          artifact: WebApp


- stage: deploy
  displayName: Deployment to SAP Cloud Platform (cf)
  jobs:
    - job: deploy
      pool:
        vmImage: 'ubuntu-latest'
      container: cfcli
      steps:
        - download: current
          artifact: WebApp
        - bash: 'cf login -u "$(CF-USER)" -p "$(CF-PASSWORD)" -a "$(CF-API)" -o "$(CF-ORG)" -s "$(CF-SPACE)" && cf deploy $(Pipeline.Workspace)/WebApp/MySampleApp.mtar -f'
```

この中でMTAプロジェクトのビルド、デプロイを定義しています。
デプロイに必要な環境情報などは、セキュリティの観点から変数化して渡してあげます。
Variablesを開くと、keyとvalueの形で変数化することが可能であるとわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277725/1dc77837-e58f-0141-af77-74eaac480ede.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277725/877bc979-1970-e3d3-84d7-7add1ca1bf83.png)

必要なのは、CF-API, CF-ORG, CF-PASSWORD, CF-SPACE, CF-USERです。
それぞれに、APIエンドポイント(https://api.cf.eu10.hana.ondemand.com など)、サブアカウント名、CFログインパスワード、スペース名、ログインユーザを定義すればよいです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277725/18c6e004-0d04-8432-74d9-3fe78c9c49fd.png)

ここまでできれば後は実行するだけです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277725/c98a072a-7f39-a33c-4ed0-8d9105db0995.png)

対象となるGitブランチを選択します。
たったこれだけでお片づけが完了です。スッキリ☆
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277725/e3724c10-5c50-8764-30d5-e0f3369998a1.png)

他の開発でもしながら放っておいている内に、勝手にビルド、デプロイが成功しております。成功すると赤枠のように緑色のバッチが付きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277725/cd3b1223-58f7-8551-9a11-292f3495b768.png)


中身を見てみると、ビルド、デプロイの過程で出力されたログも見られます。
この辺りはCF-CLIで操作した時とほとんど変わらないログが吐かれているはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277725/4c75303e-2329-39be-7f4e-d5f9371e220e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277725/e235bb7b-807c-7971-58bf-adfa1cd274d1.png)


実際に、CF環境を見てみるとworkshop1128の中にあるモジュールたちがちゃんとデプロイされていることがわかります。
なんて素敵なんでしょう・・//
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277725/2464bc02-91b1-b99c-4f7b-ff693ce03466.png)

## おわりに -ココロトキメク

いかがでしたか？
意外と簡単にDevOps環境って構築できると思えたのではないでしょうか？
今後はテストコードの実行などもパイプライン上で行うことで、よりCI/CDの概念に近づけたり、Ansibleのようなサービスを使って構成管理を実現することがしたいですね☆

みなさまココロトキメク開発ライフを楽しみましょう～