diff --git a/DockerfileServerDictation.dockerfile b/DockerfileServerDictation.dockerfile index aa666ba..2efefee 100644 --- a/DockerfileServerDictation.dockerfile +++ b/DockerfileServerDictation.dockerfile @@ -20,4 +20,6 @@ RUN mkdir build \ COPY --from=build-container app/dictation_server/dist/ dist/ COPY --from=build-container app/dictation_server/.env ./ COPY --from=build-container app/dictation_server/node_modules/ node_modules/ +ARG BUILD_VERSION +ENV BUILD_VERSION=${BUILD_VERSION} CMD ["node", "./dist/main.js" ] diff --git a/azure-pipelines-production.yml b/azure-pipelines-production.yml index 45eba43..e3a4ada 100644 --- a/azure-pipelines-production.yml +++ b/azure-pipelines-production.yml @@ -1,5 +1,4 @@ -# Pipeline側でKeyVaultやDocker、AppService等に対する操作権限を持ったServiceConenctionを作成し、 -# 環境変数 AZURE_SERVICE_CONNECTION の値としてServiceConenction名を設定しておくこと +# Pipeline側でKeyVaultやDocker、AppService等に対する操作権限を持ったServiceConenctionを作成しておくこと # また、環境変数 STATIC_DICTATION_DEPLOYMENT_TOKEN の値として静的WebAppsのデプロイトークンを設定しておくこと trigger: tags: @@ -26,43 +25,40 @@ jobs: fi displayName: 'タグが付けられたCommitがmainブランチに存在するか確認' - job: backend_deploy + dependsOn: initialize + condition: succeeded('initialize') displayName: Backend Deploy pool: - name: odms-deploy-pipeline + vmImage: ubuntu-latest steps: - checkout: self clean: true fetchDepth: 1 - - task: AzureRmWebAppDeployment@4 + - task: AzureWebAppContainer@1 inputs: - ConnectionType: 'AzureRM' - azureSubscription: $(AZURE_SERVICE_CONNECTION) - appType: 'webAppContainer' - WebAppName: 'app-odms-dictation-prod' - ResourceGroupName: 'prod-application-rg' - DockerNamespace: 'crodmsregistrymaintenance.azurecr.io' - DockerRepository: '$(Build.Repository.Name)/staging/dictation' - DockerImageTag: '$(Build.SourceVersion)' + azureSubscription: 'omds-service-connection-prod' + appName: 'app-odms-dictation-prod' + deployToSlotOrASE: true + resourceGroupName: 'odms-prod-rg' + slotName: 'staging' + containers: 'crodmsregistrymaintenance.azurecr.io/odmscloud/test/dictation:$(Build.SourceVersion)' + # TODO: stagingパイプライン実装時、staging用のイメージに変更する - job: frontend_deploy + dependsOn: backend_deploy + condition: succeeded('backend_deploy') displayName: Deploy Frontend Files variables: storageAccountName: saomdspipeline containerName: staging pool: - name: odms-deploy-pipeline + vmImage: ubuntu-latest steps: - checkout: self clean: true fetchDepth: 1 - - task: AzureKeyVault@2 - displayName: 'Azure Key Vault: kv-odms-secret-prod' - inputs: - ConnectedServiceName: $(AZURE_SERVICE_CONNECTION) - KeyVaultName: kv-odms-secret-prod - SecretsFilter: '*' - task: AzureCLI@2 inputs: - azureSubscription: $(AZURE_SERVICE_CONNECTION) + azureSubscription: 'omds-service-connection-prod' scriptType: 'bash' scriptLocation: 'inlineScript' inlineScript: | @@ -88,15 +84,42 @@ jobs: is_static_export: false verbose: false azure_static_web_apps_api_token: $(STATIC_DICTATION_DEPLOYMENT_TOKEN) -- job: migration - condition: succeeded('initialize') - displayName: DB migration - dependsOn: - - initialize - - backend_deploy - - frontend_deploy +- job: smoke_test + dependsOn: frontend_deploy + condition: succeeded('frontend_deploy') + displayName: 'smoke test' pool: - name: db-migrate-pipelines + name: odms-deploy-pipeline + steps: + - checkout: self + clean: true + fetchDepth: 1 + # スモークテスト用にjobを確保 +- job: swap_slot + dependsOn: smoke_test + condition: succeeded('smoke_test') + displayName: 'Swap Staging and Production' + pool: + name: odms-deploy-pipeline + steps: + - checkout: self + clean: true + fetchDepth: 1 + - task: AzureAppServiceManage@0 + displayName: 'Azure App Service Manage: app-odms-dictation-prod' + inputs: + azureSubscription: 'omds-service-connection-prod' + action: 'Swap Slots' + WebAppName: 'app-odms-dictation-prod' + ResourceGroupName: 'odms-prod-rg' + SourceSlot: 'staging' + SwapWithProduction: true +- job: migration + dependsOn: swap_slot + condition: succeeded('swap_slot') + displayName: DB migration + pool: + name: odms-deploy-pipeline steps: - checkout: self clean: true @@ -104,7 +127,7 @@ jobs: - task: AzureKeyVault@2 displayName: 'Azure Key Vault: kv-odms-secret-prod' inputs: - ConnectedServiceName: $(AZURE_SERVICE_CONNECTION) + ConnectedServiceName: 'omds-service-connection-prod' KeyVaultName: kv-odms-secret-prod - task: CmdLine@2 displayName: migration diff --git a/azure-pipelines-staging-test.yml b/azure-pipelines-staging-test.yml new file mode 100644 index 0000000..87ca222 --- /dev/null +++ b/azure-pipelines-staging-test.yml @@ -0,0 +1,235 @@ +# Pipeline側でKeyVaultやDocker、AppService等に対する操作権限を持ったServiceConenctionを作成しておくこと +# また、環境変数 STATIC_DICTATION_DEPLOYMENT_TOKEN の値として静的WebAppsのデプロイトークンを設定しておくこと +trigger: + # branches: + # include: + # - main + tags: + include: + - stage-* + +jobs: +- job: initialize + displayName: Initialize + pool: + vmImage: ubuntu-latest + steps: + - checkout: self + clean: true + fetchDepth: 1 + persistCredentials: true + # - script: | + # git fetch origin main:main + # if git merge-base --is-ancestor $(Build.SourceVersion) main; then + # echo "This commit is in the main branch." + # else + # echo "This commit is not in the main branch." + # exit 1 + # fi + # displayName: 'タグが付けられたCommitがmainブランチに存在するか確認' +- job: backend_build + dependsOn: initialize + condition: succeeded('initialize') + displayName: Build And Push Backend Image + pool: + name: odms-deploy-pipeline + steps: + - checkout: self + clean: true + fetchDepth: 1 + - task: Npm@1 + displayName: npm ci + inputs: + command: ci + workingDir: dictation_server + verbose: false + - task: AzureKeyVault@2 + displayName: 'Azure Key Vault: kv-odms-secret-stg' + inputs: + ConnectedServiceName: 'omds-service-connection-stg' + KeyVaultName: kv-odms-secret-stg + SecretsFilter: '*' + - task: Bash@3 + displayName: Bash Script (Test) + inputs: + targetType: inline + script: | + cd dictation_server + npm run test + env: + JWT_PUBLIC_KEY: $(token-public-key) + SENDGRID_API_KEY: $(sendgrid-api-key) + NOTIFICATION_HUB_NAME: $(notification-hub-name) + NOTIFICATION_HUB_CONNECT_STRING: $(notification-hub-connect-string) + STORAGE_ACCOUNT_NAME_US: $(storage-account-name-us) + STORAGE_ACCOUNT_NAME_AU: $(storage-account-name-au) + STORAGE_ACCOUNT_NAME_EU: $(storage-account-name-eu) + STORAGE_ACCOUNT_KEY_US: $(storage-account-key-us) + STORAGE_ACCOUNT_KEY_AU: $(storage-account-key-au) + STORAGE_ACCOUNT_KEY_EU: $(storage-account-key-eu) + STORAGE_ACCOUNT_ENDPOINT_US: $(storage-account-endpoint-us) + STORAGE_ACCOUNT_ENDPOINT_AU: $(storage-account-endpoint-au) + STORAGE_ACCOUNT_ENDPOINT_EU: $(storage-account-endpoint-eu) + ADB2C_TENANT_ID: $(adb2c-tenant-id) + ADB2C_CLIENT_ID: $(adb2c-client-id) + ADB2C_CLIENT_SECRET: $(adb2c-client-secret) + - task: Docker@0 + displayName: build + inputs: + azureSubscriptionEndpoint: 'omds-service-connection-stg' + azureContainerRegistry: '{"loginServer":"crodmsregistrymaintenance.azurecr.io", "id" : "/subscriptions/108fb131-cdca-4729-a2be-e5bd8c0b3ba7/resourceGroups/maintenance-rg/providers/Microsoft.ContainerRegistry/registries/crOdmsRegistryMaintenance"}' + dockerFile: DockerfileServerDictation.dockerfile + imageName: odmscloud/test/dictation:$(Build.SourceVersion) + buildArguments: | + BUILD_VERSION=$(Build.SourceVersion) + - task: Docker@0 + displayName: push + inputs: + azureSubscriptionEndpoint: 'omds-service-connection-stg' + azureContainerRegistry: '{"loginServer":"crodmsregistrymaintenance.azurecr.io", "id" : "/subscriptions/108fb131-cdca-4729-a2be-e5bd8c0b3ba7/resourceGroups/maintenance-rg/providers/Microsoft.ContainerRegistry/registries/crOdmsRegistryMaintenance"}' + action: Push an image + imageName: odmscloud/test/dictation:$(Build.SourceVersion) +- job: backend_deploy + dependsOn: backend_build + condition: succeeded('backend_build') + displayName: Backend Deploy + pool: + name: odms-deploy-pipeline + steps: + - checkout: self + clean: true + fetchDepth: 1 + # - task: AzureRmWebAppDeployment@4 + # inputs: + # ConnectionType: 'AzureRM' + # azureSubscription: 'omds-service-connection-stg' + # appType: 'webAppContainer' + # WebAppName: 'app-odms-dictation-stg' + # ResourceGroupName: 'stg-application-rg' + # DockerNamespace: 'crodmsregistrymaintenance.azurecr.io' + # DockerRepository: 'odmscloud/test/dictation' + # DockerImageTag: '$(Build.SourceVersion)' +- job: frontend_build + dependsOn: initialize + condition: succeeded('initialize') + displayName: Build Frontend Files + variables: + storageAccountName: saomdspipeline + containerName: staging + pool: + name: odms-deploy-pipeline + steps: + - checkout: self + clean: true + fetchDepth: 1 + - task: Npm@1 + displayName: npm ci + inputs: + command: ci + workingDir: dictation_client + verbose: false + - task: Bash@3 + displayName: Bash Script + inputs: + targetType: inline + script: cd dictation_client && npm run build + - task: ArchiveFiles@2 + inputs: + rootFolderOrFile: dictation_client/build + includeRootFolder: false + archiveType: 'zip' + archiveFile: '$(Build.ArtifactStagingDirectory)/$(Build.SourceVersion).zip' + replaceExistingArchive: true + - task: AzureCLI@2 + inputs: + azureSubscription: 'omds-service-connection-stg' + scriptType: 'bash' + scriptLocation: 'inlineScript' + inlineScript: | + az storage blob upload \ + --auth-mode login \ + --account-name $(storageAccountName) \ + --container-name $(containerName) \ + --name $(Build.SourceVersion).zip \ + --type block \ + --overwrite \ + --file $(Build.ArtifactStagingDirectory)/$(Build.SourceVersion).zip +- job: frontend_deploy + dependsOn: frontend_build + condition: succeeded('frontend_build') + displayName: Deploy Frontend Files + variables: + storageAccountName: saomdspipeline + containerName: staging + pool: + name: odms-deploy-pipeline + steps: + - checkout: self + clean: true + fetchDepth: 1 + # - task: AzureKeyVault@2 + # displayName: 'Azure Key Vault: kv-odms-secret-stg' + # inputs: + # ConnectedServiceName: 'omds-service-connection-stg' + # KeyVaultName: kv-odms-secret-stg + # SecretsFilter: '*' + # - task: AzureCLI@2 + # inputs: + # azureSubscription: 'omds-service-connection-stg' + # scriptType: 'bash' + # scriptLocation: 'inlineScript' + # inlineScript: | + # az storage blob download \ + # --auth-mode login \ + # --account-name $(storageAccountName) \ + # --container-name $(containerName) \ + # --name $(Build.SourceVersion).zip \ + # --file $(Build.SourcesDirectory)/$(Build.SourceVersion).zip + # - task: Bash@3 + # displayName: Bash Script + # inputs: + # targetType: inline + # script: unzip $(Build.SourcesDirectory)/$(Build.SourceVersion).zip -d $(Build.SourcesDirectory)/$(Build.SourceVersion) + # - task: AzureStaticWebApp@0 + # displayName: 'Static Web App: ' + # inputs: + # workingDirectory: '$(Build.SourcesDirectory)' + # app_location: '/$(Build.SourceVersion)' + # config_file_location: /dictation_client + # skip_app_build: true + # skip_api_build: true + # is_static_export: false + # verbose: false + # azure_static_web_apps_api_token: $(STATIC_DICTATION_DEPLOYMENT_TOKEN) +- job: migration + condition: succeeded('initialize') + displayName: DB migration + dependsOn: + - initialize + - backend_deploy + - frontend_deploy + pool: + name: odms-deploy-pipeline + steps: + - checkout: self + clean: true + fetchDepth: 1 + # - task: AzureKeyVault@2 + # displayName: 'Azure Key Vault: kv-odms-secret-stg' + # inputs: + # ConnectedServiceName: 'omds-service-connection-stg' + # KeyVaultName: kv-odms-secret-stg + # - task: CmdLine@2 + # displayName: migration + # inputs: + # script: >2 + # # DB接続情報書き換え + # sed -i -e "s/DB_NAME/$(db-name)/g" ./dictation_server/db/dbconfig.yml + # sed -i -e "s/DB_PASS/$(db-pass)/g" ./dictation_server/db/dbconfig.yml + # sed -i -e "s/DB_USERNAME/$(db-user)/g" ./dictation_server/db/dbconfig.yml + # sed -i -e "s/DB_PORT/$(db-port)/g" ./dictation_server/db/dbconfig.yml + # sed -i -e "s/DB_HOST/$(db-host)/g" ./dictation_server/db/dbconfig.yml + # sql-migrate --version + # cat ./dictation_server/db/dbconfig.yml + # # migration実行 + # sql-migrate up -config=./dictation_server/db/dbconfig.yml -env=ci \ No newline at end of file diff --git a/dictation_server/src/main.ts b/dictation_server/src/main.ts index dc7cb5c..b4ad979 100644 --- a/dictation_server/src/main.ts +++ b/dictation_server/src/main.ts @@ -20,6 +20,7 @@ helmetDirectives['navigate-to'] = ["'self'"]; helmetDirectives['style-src'] = ["'self'", 'https:']; helmetDirectives['report-uri'] = ["'self'"]; async function bootstrap() { + console.log(`BUILD_VERSION: ${process.env.BUILD_VERSION}`); const app = await NestFactory.create(AppModule); app.use(