<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>gcp 彙整 - 泰克哪裡去</title>
	<atom:link href="https://tech.uccu.website/tag/gcp/feed" rel="self" type="application/rss+xml" />
	<link>https://tech.uccu.website/tag/gcp</link>
	<description>一個科技相關的隨手記錄網站</description>
	<lastBuildDate>Sun, 25 Sep 2022 14:11:36 +0000</lastBuildDate>
	<language>zh-TW</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.1</generator>
<site xmlns="com-wordpress:feed-additions:1">119574712</site>	<item>
		<title>【2022鐵人賽】基本版-建立CI Pipeline(3)</title>
		<link>https://tech.uccu.website/2022ironman-day10-ci-pipeline-deploy-dev-to-cloudrun.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=2022ironman-day10-ci-pipeline-deploy-dev-to-cloudrun</link>
					<comments>https://tech.uccu.website/2022ironman-day10-ci-pipeline-deploy-dev-to-cloudrun.html#respond</comments>
		
		<dc:creator><![CDATA[鳴人]]></dc:creator>
		<pubDate>Sun, 25 Sep 2022 13:59:09 +0000</pubDate>
				<category><![CDATA[2022鐵人賽]]></category>
		<category><![CDATA[Azure DevOps]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Google雲端GCP]]></category>
		<category><![CDATA[iThome鐵人賽]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[雲端]]></category>
		<category><![CDATA[2022ironman]]></category>
		<category><![CDATA[azure devops]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[gcp]]></category>
		<guid isPermaLink="false">https://tech.uccu.website/?p=1930</guid>

					<description><![CDATA[<p>這篇內容利用了Google建置的gcloud的Docker Image來執行gcloud CLI工具的指令，除了先前建立的服務帳戶要補上一個IAM的角色之外，透過Container執行gcloud指令還有一個重點，它將會是能不能夠正常透過Container執行gcloud的關鍵！</p>
<p>這篇文章 <a href="https://tech.uccu.website/2022ironman-day10-ci-pipeline-deploy-dev-to-cloudrun.html">【2022鐵人賽】基本版-建立CI Pipeline(3)</a> 最早出現於 <a href="https://tech.uccu.website">泰克哪裡去</a>。</p>
]]></description>
										<content:encoded><![CDATA[<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-recalc-dims="1" fetchpriority="high" decoding="async" width="990" height="150" src="https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/00-DevelopCI-Flow.png?resize=990%2C150&#038;ssl=1" alt="" class="wp-image-1931" srcset="https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/00-DevelopCI-Flow.png?w=990&amp;ssl=1 990w, https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/00-DevelopCI-Flow.png?resize=300%2C45&amp;ssl=1 300w, https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/00-DevelopCI-Flow.png?resize=768%2C116&amp;ssl=1 768w" sizes="(max-width: 990px) 100vw, 990px" /><figcaption>Develop CI流程</figcaption></figure></div>


<p>上面這張圖是<a href="https://tech.uccu.website/2022ironman-day3-flow-plan.html" target="_blank" rel="noreferrer noopener">流程規劃說明</a>裡面畫的Develop CI Pipeline流程，我們已經在前兩篇完成了Build(Code)、Build Image，剩下最後一步就是Deploy Dev環境，這一篇就來完成這最後一步吧！</p>



<pre class="wp-block-prismatic-blocks"><code class="language-yaml">trigger:
- none

pool:
  vmImage: ubuntu-latest

resources:
  repositories:
  - repository: sources
    type: git
    name: ironman2022/NetApp
    ref: Develop
    trigger:
      branches:
        include:
          - Develop

variables:
  pipelineArtifact: output
  buildResultZipName: buildResult.zip
  slnOrCsprojName: IronmanWeb.sln
  imgRepository: &#039;asia-east1-docker.pkg.dev/feisty-mechanic-363012/ironman2022/ironmanweb&#039;
  buildDockerfile: &#039;Dockerfile&#039;
  imgRegistryService: &#039;GCPArtifactRegistry&#039;
  cloudRunServiceName: ironmanweb
  cloudRunPort: 8080
  cloudRunRegion: asia-east1
  cloudRunProjectId: feisty-mechanic-363012
  gcpAuthJsonFile: ironman2022-gcp-key.json

jobs:
  - job: BuildCode
    steps:
      - checkout: sources
        clean: true
      - script: |
          export UID=$(id -u)
          export GID=$(id -g)
          docker run --user $UID:$GID --rm \
          -v $(Build.SourcesDirectory):/tmp/source \
          -v $(Build.BinariesDirectory):/tmp/publish \
          -e DOTNET_CLI_HOME=/tmp/.dotnet \
          mcr.microsoft.com/dotnet/sdk:6.0-alpine \
          dotnet publish /tmp/source/$(slnOrCsprojName) \
          -c release \
          -o /tmp/publish
        displayName: Dotnet Build
      - task: ArchiveFiles@2
        displayName: 壓縮成zip
        inputs:
          rootFolderOrFile: $(Build.BinariesDirectory)
          includeRootFolder: false
          archiveType: &#039;zip&#039;
          archiveFile: &#039;$(Build.ArtifactStagingDirectory)/zipFiles/$(buildResultZipName)&#039;
          replaceExistingArchive: true
      - task: PublishBuildArtifacts@1
        displayName: 上傳到Pipeline Artifact
        inputs:
          PathtoPublish: &#039;$(Build.ArtifactStagingDirectory)/zipFiles/$(buildResultZipName)&#039;
          ArtifactName: &#039;$(pipelineArtifact)&#039;
          publishLocation: &#039;Container&#039;
  - job: BuildImage
    dependsOn: BuildCode
    steps:
      - task: DownloadBuildArtifacts@0
        displayName: 下載Pipeline Artifact
        inputs:
          buildType: &#039;current&#039;
          cleanDestinationFolder: true
          downloadType: &#039;single&#039;
          artifactName: &#039;$(pipelineArtifact)&#039;
          downloadPath: &#039;$(System.ArtifactsDirectory)/&#039;
      - task: ExtractFiles@1
        displayName: Unzip zip
        inputs:
          archiveFilePatterns: &#039;$(System.ArtifactsDirectory)/$(pipelineArtifact)/$(buildResultZipName)&#039;
          destinationFolder: &#039;$(System.ArtifactsDirectory)/BuildImage&#039;
          cleanDestinationFolder: true
          overwriteExistingFiles: true
      - task: Docker@2
        displayName: Build image
        inputs:
          repository: &#039;$(imgRepository)&#039;
          command: &#039;build&#039;
          Dockerfile: $(buildDockerfile)
          buildContext: &#039;$(System.ArtifactsDirectory)/BuildImage&#039;
          arguments: &#039;--no-cache&#039;
          tags: |
            latest
      - task: Docker@2
        displayName: &quot;Login to Container Registry&quot;
        inputs:
          command: login
          containerRegistry: $(imgRegistryService)
      - task: Bash@3
        displayName: Push docker image
        inputs:
          targetType: &#039;inline&#039;
          script: |
            docker push -a $(imgRepository)
  - job: DeployCloudRun
    dependsOn: BuildImage
    steps:
      - task: Bash@3
        displayName: Deploy docker image to cloudrun
        inputs:
          targetType: &#039;inline&#039;
          script: |
            docker run --rm \
            -v $(Build.SourcesDirectory)/$(gcpAuthJsonFile):/gcp/cloudKey.json \
            asia.gcr.io/google.com/cloudsdktool/google-cloud-cli:latest \
            bash -c &quot;gcloud auth login --cred-file=/gcp/cloudKey.json &amp;&amp; gcloud run deploy $(cloudRunServiceName) --set-env-vars=Ironman=$(Build.BuildId) --image $(imgRepository) --region $(cloudRunRegion) --project $(cloudRunProjectId) --allow-unauthenticated&quot;</code></pre>



<p>哇！一來就是一長串的YAML內容…</p>



<p>不不不，你如果是用VSCode打開，幾乎可以把前面兩個Job折疊起來，這邊增加的DeployCloudRun Job也只有一個Bash的task，不多的。</p>



<p>就讓我娓娓道來這篇主要增加的內容吧！</p>



<pre class="wp-block-prismatic-blocks"><code class="language-yaml">  cloudRunServiceName: ironmanweb
  cloudRunPort: 8080
  cloudRunRegion: asia-east1
  cloudRunProjectId: feisty-mechanic-363012
  gcpAuthJsonFile: ironman2022-gcp-key.json</code></pre>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-recalc-dims="1" decoding="async" width="602" height="240" src="https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/01-CloudRunList.png?resize=602%2C240&#038;ssl=1" alt="" class="wp-image-1936" srcset="https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/01-CloudRunList.png?w=602&amp;ssl=1 602w, https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/01-CloudRunList.png?resize=300%2C120&amp;ssl=1 300w" sizes="(max-width: 602px) 100vw, 602px" /></figure></div>


<p>cloudRunServiceName就是圖中Cloud Run的名稱。</p>



<p>cloudRunPort設定為8080是在appsettings.json中設定了Kestrel的Http是使用8080 Port，也就是container內會監聽什麼Port，對應docker指令就是-p 80:8080。</p>



<p>cloudRunRegion則是CloudRun佈署的區域(機房)。</p>



<p>cloudRunProjectId可以直接從Google Cloud管理介面的URL得知，也就是在上圖畫面的時候，看一下瀏覽器上的網址列，「&amp;project=」後面的就是了，或是選擇Project的下拉選單：</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-recalc-dims="1" decoding="async" width="1024" height="399" src="https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/02-GCPFindProjectId-1024x399.png?resize=1024%2C399&#038;ssl=1" alt="" class="wp-image-1938" srcset="https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/02-GCPFindProjectId.png?resize=1024%2C399&amp;ssl=1 1024w, https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/02-GCPFindProjectId.png?resize=300%2C117&amp;ssl=1 300w, https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/02-GCPFindProjectId.png?resize=768%2C299&amp;ssl=1 768w, https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/02-GCPFindProjectId.png?w=1142&amp;ssl=1 1142w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption>Google Cloud的Project Id</figcaption></figure></div>


<p>最後的gcpAuthJsonFile則是前面幾篇用來授權的Json檔案。不過這邊要補充一下，<a href="https://tech.uccu.website/2022ironman-day4-create-registry-and-service-account.html" target="_blank" rel="noreferrer noopener">那時候</a>在新增服務帳戶的時候還少加了一個「<strong>服務帳戶使用者</strong>」角色，所以漏加這個角色繼續做下去的話，就會碰到下面的錯誤訊息：</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p></p><cite>PERMISSION_DENIED: Permission &#8216;iam.serviceaccounts.actAs&#8217; denied on service account</cite></blockquote>



<p>為了讓後面使用gcloud cli可以順利執行，所以要先在<a href="https://console.cloud.google.com/iam-admin/iam?hl=zh-TW" target="_blank" rel="noreferrer noopener">IAM</a>裡面將前面新增的服務帳戶加上「<strong>服務帳戶使用者</strong>」角色：</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-recalc-dims="1" loading="lazy" decoding="async" width="424" height="340" src="https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/03-AddGCPIAMRole.png?resize=424%2C340&#038;ssl=1" alt="" class="wp-image-1939" srcset="https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/03-AddGCPIAMRole.png?w=424&amp;ssl=1 424w, https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/03-AddGCPIAMRole.png?resize=300%2C241&amp;ssl=1 300w" sizes="auto, (max-width: 424px) 100vw, 424px" /><figcaption>新增「<strong>服務帳戶使用者</strong>」角色</figcaption></figure></div>


<p>增加角色之後不需要重新下載用於授權的Json檔案，因為有什麼角色權限不會寫在檔案裡。</p>



<p>Job越加越多，這三個Job之間其實是有相依性的，也就是說要先BuildCode之後才能夠BuildImage，接下來才能DeployCloudRun，所以在第二個和第三個Job底下分別要加上dependsOn的屬性：</p>



<pre class="wp-block-prismatic-blocks"><code class="language-yaml">- job: BuildImage
    dependsOn: BuildCode</code></pre>



<pre class="wp-block-prismatic-blocks"><code class="language-yaml">- job: DeployCloudRun
    dependsOn: BuildImage</code></pre>



<p>這個部份滿重要的，尤其是如果有<a href="https://azure.microsoft.com/zh-tw/pricing/details/devops/azure-devops-services/" target="_blank" rel="noreferrer noopener">額外購買CloudAgent的執行數量</a>時，因為Job可以在不同的Agent執行，所以它可以在同一個Pipeline同時跑多個Job(沒有設定相依的dependsOn時)，就算沒有額外購買CloudAgent的執行數量，沒設定dependsOn也無法保證它們的執行順序。BuildImage的Job相較前一篇有增加的也只有dependsOn這個屬性。</p>



<p>最後就是DeployCloudRun這個Job，裡面的內容也只有一個Bash的task，所以下面我直接貼bash script的部份：</p>



<pre class="wp-block-prismatic-blocks"><code class="language-bash">            docker run --rm \
            -v $(Build.SourcesDirectory)/$(gcpAuthJsonFile):/gcp/cloudKey.json \
            asia.gcr.io/google.com/cloudsdktool/google-cloud-cli:latest \
            bash -c &quot;gcloud auth login --cred-file=/gcp/cloudKey.json &amp;&amp; gcloud run deploy $(cloudRunServiceName) --set-env-vars=Ironman=$(Build.BuildId) --image $(imgRepository) --region $(cloudRunRegion) --project $(cloudRunProjectId) --allow-unauthenticated&quot;</code></pre>



<p>在這裡是使用google的gcloud CLI工具來執行CloudRun的佈署，不過gcloud CLI工具還是需要安裝的，要嘛是需要先裝在Agent的電腦內，而且還要去爬<a href="https://cloud.google.com/sdk/docs/install" target="_blank" rel="noreferrer noopener">官方的安裝文件</a>知道怎麼安裝，不然就是安裝在Docker Image裡面。</p>



<p>我們使用的是ClougAgent，所以Agent的環境不是我們可以控制的，每次執行也是新的vm執行起來，所以選擇後者使用google建立的gcloud CLI的Docker Image會是最理想的選擇，除了從<a href="https://hub.docker.com/r/google/cloud-sdk" target="_blank" rel="noreferrer noopener">Docker Hub</a>可以找到之外，<a href="https://cloud.google.com/sdk/docs/downloads-docker" target="_blank" rel="noreferrer noopener">官方文件</a>也有提供不同Container Registry的選擇說明。</p>



<p>使用Container來執行gcloud CLI，我們可以省去安裝的麻煩事，只要會使用就可以了，這讓我們可以更專注在其它的設計部份。</p>



<p>script中的重點只有第二行和最後一行，分別是把授權用的Json檔案關聯到Container裡面，以便讓裡面的gcloud CLI工具可以讀取到內容進行login動作，以及最後一行包含lgoin的指令。</p>



<p>最後一行的指令有個重點，就是我們必須先使用gloud auth login的指令讓CLI工具登入，接著才能執行CloudRun的Deploy指令，也就是說要執行的指令有兩個，所以使用了「&amp;&amp;」這個管道符號讓它接續執行，但是直接這樣接在Image Repository後面是行不通的，「&amp;&amp;」符號的前面會跟最前面的docker run指令合起來作為第一個指令，後面的則是host環境接續docker run指令執行的第二個指令。</p>



<p>所以在這個地方必須是讓docker run執行起來的contianer是執行bash程式，後面接著要執行的指令字串(用引號包起來)，也因為是一整個字串，所以沒辦法使用「\\」換行，就會是一行很長的指令，下面為了方便閱讀，把它們拆開來說明。</p>



<pre class="wp-block-prismatic-blocks"><code class="language-bash">gcloud auth login --cred-file=/gcp/cloudKey.json</code></pre>



<p>「&amp;&amp;」符號前的這一行是將gcloud CLI工具登入，使用&#8211;cred-file參數帶入Json檔案，後面的路徑是Container內的路徑，也就是前面-v設定的部份。</p>



<pre class="wp-block-prismatic-blocks"><code class="language-batch">gcloud run deploy $(cloudRunServiceName) --set-env-vars=Ironman=$(Build.BuildId) --image $(imgRepository) --region $(cloudRunRegion) --project $(cloudRunProjectId) --allow-unauthenticated</code></pre>



<p>「&amp;&amp;」符號後面的指令我依參數拆行來看應該就很清楚，因為大部份都是上面設定的變數，已經有說明過了。</p>



<p>&#8211;set-env-vars的參數是設定CloudRun放入的環境變數(還記得前面的Ironman環境變數嗎？)，&#8211;allow-unauthenticated則是允許訪客瀏覽，不然CloudRun可能不會正常回應頁面。</p>



<p>gcloud run deploy $(cloudRunServiceName) <br>&#8211;set-env-vars=Ironman=$(Build.BuildId) <br>&#8211;image $(imgRepository) <br>&#8211;region $(cloudRunRegion) <br>&#8211;project $(cloudRunProjectId) <br>&#8211;allow-unauthenticated</p>



<p>關於CloudRun在gcloud CLI可以設定的更多參數部份，請參考<a href="https://cloud.google.com/sdk/gcloud/reference/run/deploy" target="_blank" rel="noreferrer noopener">官方文件的頁面</a>，之後的文章還會把部份參數用上。</p>



<p>最後，在CI Pipeline成功執行完之後，就可以在對應的Task log中看到gcloud CLI工具吐出來的CloudRun網址，這樣就不用進入到GCP的管理介面去查看。</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="689" src="https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/04-DeployCloudRunLog-1024x689.png?resize=1024%2C689&#038;ssl=1" alt="" class="wp-image-1940" srcset="https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/04-DeployCloudRunLog.png?resize=1024%2C689&amp;ssl=1 1024w, https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/04-DeployCloudRunLog.png?resize=300%2C202&amp;ssl=1 300w, https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/04-DeployCloudRunLog.png?resize=768%2C516&amp;ssl=1 768w, https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/04-DeployCloudRunLog.png?w=1316&amp;ssl=1 1316w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure></div>


<p>最後補充一個小細節，就是在這三個Job之中，只有BuildCode這個Job中有明確的加上checkout: sources，並且身份驗證的Json檔案是放在Pipelines這個Git Repository裡面，但是在後面的BuildImage和DeployCloudRun並沒有明確加上checkout動作卻會(可以)取得Pipelines這個Git Repository裡面的檔案，也沒有在resources.repositories底下設定Pipelines，主要是因為這裡的Pipeline YAML檔案就是放在Pipelines這個Git Repository裡面，所以隱含了checkout: self這個動作，替我們省下了一些設定。(下圖紅框與藍框的差異)</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="336" height="1024" src="https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/05-DefaultCheckoutSelfRepo-336x1024.png?resize=336%2C1024&#038;ssl=1" alt="" class="wp-image-1941" srcset="https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/05-DefaultCheckoutSelfRepo.png?resize=336%2C1024&amp;ssl=1 336w, https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/05-DefaultCheckoutSelfRepo.png?resize=98%2C300&amp;ssl=1 98w, https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/05-DefaultCheckoutSelfRepo.png?resize=504%2C1536&amp;ssl=1 504w, https://i0.wp.com/storage.googleapis.com/stateless-tech-uccu-website/2022/09/05-DefaultCheckoutSelfRepo.png?w=547&amp;ssl=1 547w" sizes="auto, (max-width: 336px) 100vw, 336px" /></figure></div><p>這篇文章 <a href="https://tech.uccu.website/2022ironman-day10-ci-pipeline-deploy-dev-to-cloudrun.html">【2022鐵人賽】基本版-建立CI Pipeline(3)</a> 最早出現於 <a href="https://tech.uccu.website">泰克哪裡去</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://tech.uccu.website/2022ironman-day10-ci-pipeline-deploy-dev-to-cloudrun.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1930</post-id>	</item>
	</channel>
</rss>
