1. Giriş
Genel Bakış
Bu codelab'de, kaynak kodu değişikliklerinizi bir GitHub deposuna aktardığınızda Cloud Run'ı uygulamanızın yeni sürümlerini otomatik olarak derleyip dağıtacak şekilde yapılandıracaksınız.
Bu demo uygulaması, kullanıcı verilerini firestore'a kaydeder ancak verilerin yalnızca bir kısmı düzgün şekilde kaydedilir. Sürekli dağıtımlar yapılandıracaksınız. Bu şekilde GitHub deponuza hata düzeltmesi aktardığınızda düzeltme yeni bir düzeltmede otomatik olarak kullanıma sunulacak.
Neler öğreneceksiniz?
- Cloud Shell Düzenleyici ile Express web uygulaması yazma
- Sürekli dağıtımlar için GitHub hesabınızı Google Cloud'a bağlayın
- Uygulamanızı otomatik olarak Cloud Run'a dağıtma
- HTMX ve TailwindCSS'yi nasıl kullanacağınızı öğrenin
2. Kurulum ve Gereksinimler
Ön koşullar
- GitHub hesabınız var ve kod oluşturma ve kod depolarına aktarma konusunda bilgi sahibisiniz.
- Cloud Console'a giriş yaptınız.
- Daha önce bir Cloud Run hizmeti dağıttınız. Örneğin, başlamak için kaynak kodundan web hizmeti dağıtma başlıklı makaledeki adımları uygulayabilirsiniz.
Cloud Shell'i etkinleştirme
- Cloud Console'da, Cloud Shell'i etkinleştir simgesini tıklayın.
Cloud Shell'i ilk kez başlatıyorsanız ne olduğunu açıklayan bir ara ekran gösterilir. Ara bir ekran görüntülendiyse Devam'ı tıklayın.
Temel hazırlık ve Cloud Shell'e bağlanmak yalnızca birkaç dakika sürer.
Gereken tüm geliştirme araçları bu sanal makinede yüklüdür. 5 GB boyutunda kalıcı bir ana dizin sunar ve Google Cloud'da çalışarak ağ performansını ve kimlik doğrulamasını büyük ölçüde iyileştirir. Bu codelab'deki çalışmalarınızın tamamı olmasa bile büyük bir kısmı tarayıcıyla yapılabilir.
Cloud Shell'e bağlandıktan sonra kimliğinizin doğrulandığını ve projenin proje kimliğinize ayarlandığını göreceksiniz.
- Kimlik doğrulamanızın tamamlandığını onaylamak için Cloud Shell'de aşağıdaki komutu çalıştırın:
gcloud auth list
Komut çıkışı
Credentialed Accounts ACTIVE ACCOUNT * <my_account>@<my_domain.com> To set the active account, run: $ gcloud config set account `ACCOUNT`
- gcloud komutunun projenizi bildiğini onaylamak için Cloud Shell'de aşağıdaki komutu çalıştırın:
gcloud config list project
Komut çıkışı
[core] project = <PROJECT_ID>
Doğru değilse aşağıdaki komutla ayarlayabilirsiniz:
gcloud config set project <PROJECT_ID>
Komut çıkışı
Updated property [core/project].
3. API'leri Etkinleştirin ve Ortam Değişkenlerini Ayarlayın
API'leri etkinleştir
Bu codelab'de aşağıdaki API'lerin kullanılması gerekir. Bu API'leri şu komutu çalıştırarak etkinleştirebilirsiniz:
gcloud services enable run.googleapis.com \ cloudbuild.googleapis.com \ firestore.googleapis.com \ iamcredentials.googleapis.com
Ortam değişkenlerini ayarlama
Bu codelab'de kullanılacak ortam değişkenlerini ayarlayabilirsiniz.
REGION=<YOUR-REGION> PROJECT_ID=<YOUR-PROJECT-ID> PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)') SERVICE_ACCOUNT="firestore-accessor" SERVICE_ACCOUNT_ADDRESS=$SERVICE_ACCOUNT@$PROJECT_ID.iam.gserviceaccount.com
4. Hizmet hesabı oluşturma
Bu hizmet hesabı, Cloud Run tarafından Vertex AI Gemini API'yi çağırmak için kullanılır. Bu hizmet hesabı ayrıca Firestore okuma, yazma ve Secret Manager'daki gizli anahtarları okuma iznine de sahip olur.
Öncelikle şu komutu çalıştırarak hizmet hesabını oluşturun:
gcloud iam service-accounts create $SERVICE_ACCOUNT \ --display-name="Cloud Run access to Firestore"
Şimdi hizmet hesabına Firestore'a okuma ve yazma erişimi verin.
gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:$SERVICE_ACCOUNT_ADDRESS \ --role=roles/datastore.user
5. Firebase projesi oluşturma ve yapılandırma
- Firebase konsolunda Proje ekle'yi tıklayın.
- <YOUR_PROJECT_ID> değerini girin mevcut Google Cloud projelerinizden birine Firebase'i ekleyin
- İstenirse Firebase şartlarını inceleyip kabul edin.
- Devam'ı tıklayın.
- Firebase faturalandırma planını onaylamak için Planı Onayla'yı tıklayın.
- Bu codelab için Google Analytics'i etkinleştirmek isteğe bağlıdır.
- Firebase'i ekle'yi tıklayın.
- Proje oluşturulduktan sonra Continue (Devam) seçeneğini tıklayın.
- Build (Derleme) menüsünde, Firestore database'i (Firestore veritabanı) tıklayın.
- Create database'i (Veritabanı oluştur) tıklayın.
- Konum açılır menüsünden bölgenizi seçip İleri'yi tıklayın.
- Varsayılan Üretim modunda başlat seçeneğini kullanın, ardından Oluştur'u tıklayın.
6. Uygulamayı yazma
İlk olarak, kaynak kodu için bir dizin oluşturun ve bu dizin için cd'yi kullanın.
mkdir cloud-run-github-cd-demo && cd $_
Ardından, aşağıdaki içeriğe sahip bir package.json
dosyası oluşturun:
{ "name": "cloud-run-github-cd-demo", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "node app.js", "nodemon": "nodemon app.js", "tailwind-dev": "npx tailwindcss -i ./input.css -o ./public/output.css --watch", "tailwind": "npx tailwindcss -i ./input.css -o ./public/output.css", "dev": "npm run tailwind && npm run nodemon" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "@google-cloud/firestore": "^7.3.1", "axios": "^1.6.7", "express": "^4.18.2", "htmx.org": "^1.9.10" }, "devDependencies": { "nodemon": "^3.1.0", "tailwindcss": "^3.4.1" } }
İlk olarak aşağıdaki içerikle bir app.js
kaynak dosyası oluşturun. Bu dosya, hizmetin giriş noktasını ve uygulamanın ana mantığını içerir.
const express = require("express"); const app = express(); app.use(express.urlencoded({ extended: true })); app.use(express.json()); const path = require("path"); const { get } = require("axios"); const { Firestore } = require("@google-cloud/firestore"); const firestoreDb = new Firestore(); const fs = require("fs"); const util = require("util"); const { spinnerSvg } = require("./spinnerSvg.js"); const service = process.env.K_SERVICE; const revision = process.env.K_REVISION; app.use(express.static("public")); app.get("/edit", async (req, res) => { res.send(`<form hx-post="/update" hx-target="this" hx-swap="outerHTML"> <div> <p> <label>Name</label> <input class="border-2" type="text" name="name" value="Cloud"> </p><p> <label>Town</label> <input class="border-2" type="text" name="town" value="Nibelheim"> </p> </div> <div class="flex items-center mr-[10px] mt-[10px]"> <button class="btn bg-blue-500 text-white px-4 py-2 rounded-lg text-center text-sm font-medium mr-[10px]">Submit</button> <button class="btn bg-gray-200 text-gray-800 px-4 py-2 rounded-lg text-center text-sm font-medium mr-[10px]" hx-get="cancel">Cancel</button> ${spinnerSvg} </div> </form>`); }); app.post("/update", async function (req, res) { let name = req.body.name; let town = req.body.town; const doc = firestoreDb.doc(`demo/${name}`); //TODO: fix this bug await doc.set({ name: name /* town: town */ }); res.send(`<div hx-target="this" hx-swap="outerHTML" hx-indicator="spinner"> <p> <div><label>Name</label>: ${name}</div> </p><p> <div><label>Town</label>: ${town}</div> </p> <button hx-get="/edit" class="bg-blue-500 text-white px-4 py-2 rounded-lg text-sm font-medium mt-[10px]" > Click to update </button> </div>`); }); app.get("/cancel", (req, res) => { res.send(`<div hx-target="this" hx-swap="outerHTML"> <p> <div><label>Name</label>: Cloud</div> </p><p> <div><label>Town</label>: Nibelheim</div> </p> <div> <button hx-get="/edit" class="bg-blue-500 text-white px-4 py-2 rounded-lg text-sm font-medium mt-[10px]" > Click to update </button> </div> </div>`); }); const port = parseInt(process.env.PORT) || 8080; app.listen(port, async () => { console.log(`booth demo: listening on port ${port}`); //serviceMetadata = helper(); }); app.get("/helper", async (req, res) => { let region = ""; let projectId = ""; let div = ""; try { // Fetch the token to make a GCF to GCF call const response1 = await get( "http://metadata.google.internal/computeMetadata/v1/project/project-id", { headers: { "Metadata-Flavor": "Google" } } ); // Fetch the token to make a GCF to GCF call const response2 = await get( "http://metadata.google.internal/computeMetadata/v1/instance/region", { headers: { "Metadata-Flavor": "Google" } } ); projectId = response1.data; let regionFull = response2.data; const index = regionFull.lastIndexOf("/"); region = regionFull.substring(index + 1); div = ` <div> This created the revision <code>${revision}</code> of the Cloud Run service <code>${service}</code> in <code>${region}</code> for project <code>${projectId}</code>. </div>`; } catch (ex) { // running locally div = `<div> This is running locally.</div>`; } res.send(div); });
spinnerSvg.js
adlı bir dosya oluştur
module.exports.spinnerSvg = `<svg id="spinner" alt="Loading..." class="htmx-indicator animate-spin -ml-1 mr-3 h-5 w-5 text-blue-500" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" > <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" ></circle> <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" ></path> </svg>`;
tailwindCSS için bir input.css
dosyası oluşturun
@tailwind base; @tailwind components; @tailwind utilities;
tailwindCSS için tailwind.config.js
dosyasını oluşturun.
/** @type {import('tailwindcss').Config} */ module.exports = { content: ["./**/*.{html,js}"], theme: { extend: {} }, plugins: [] };
Sonra da bir .gitignore
dosyası oluşturun.
node_modules/ npm-debug.log coverage/ package-lock.json .DS_Store
Şimdi yeni bir public
dizini oluşturun.
mkdir public cd public
Ayrıca bu herkese açık dizinde, kullanıcı arabirimi için htmx kullanacak olan index.html
dosyasını oluşturun.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <script src="https://unpkg.com/htmx.org@1.9.10" integrity="sha384-D1Kt99CQMDuVetoL1lrYwg5t+9QdHe7NLX/SoJYkXDFfX37iInKRy5xLSi8nO7UC" crossorigin="anonymous" ></script> <link href="./output.css" rel="stylesheet" /> <title>Demo 1</title> </head> <body class="font-sans bg-body-image bg-cover bg-center leading-relaxed" > <div class="container max-w-[700px] mt-[50px] ml-auto mr-auto"> <div class="hero flex items-center"> <div class="message text-base text-center mb-[24px]"> <h1 class="text-2xl font-bold mb-[10px]"> It's running! </h1> <div class="congrats text-base font-normal"> Congratulations, you successfully deployed your service to Cloud Run. </div> </div> </div> <div class="details mb-[20px]"> <p> <div hx-trigger="load" hx-get="/helper" hx-swap="innerHTML" hx-target="this">Hello</div> </p> </div> <p class="callout text-sm text-blue-700 font-bold pt-4 pr-6 pb-4 pl-10 leading-tight" > You can deploy any container to Cloud Run that listens for HTTP requests on the port defined by the <code>PORT</code> environment variable. Cloud Run will scale automatically based on requests and you never have to worry about infrastructure. </p> <h1 class="text-2xl font-bold mt-[40px] mb-[20px]"> Persistent Storage Example using Firestore </h1> <div hx-target="this" hx-swap="outerHTML"> <p> <div><label>Name</label>: Cloud</div> </p><p> <div><label>Town</label>: Nibelheim</div> </p> <div> <button hx-get="/edit" class="bg-blue-500 text-white px-4 py-2 rounded-lg text-sm font-medium mt-[10px]" > Click to update </button> </div> </div> <h1 class="text-2xl font-bold mt-[40px] mb-[20px]"> What's next </h1> <p class="next text-base mt-4 mb-[20px]"> You can build this demo yourself! </p> <p class="cta"> <button class="bg-blue-500 text-white px-4 py-2 rounded-lg text-center text-sm font-medium" > VIEW CODELAB </button> </p> </div> </body> </html>
7. Uygulamayı yerel olarak çalıştırma
Bu bölümde, kullanıcı verileri kaydetmeye çalıştığında uygulamada bir hata olduğunu onaylamak için uygulamayı yerel olarak çalıştıracaksınız.
İlk olarak, Firestore'a erişmek için Datastore Kullanıcısı rolüne sahip olmanız gerekir (kimlik doğrulama için kimliğinizi kullanıyorsanız, ör. Cloud Shell'de çalıştırıyorsanız) veya daha önce oluşturulmuş kullanıcı hesabının kimliğine bürünebilirsiniz.
Yerel olarak çalıştırırken ADC kullanma
Cloud Shell'de çalışıyorsanız zaten bir Google Compute Engine sanal makinesinde çalıştırıyorsunuz demektir. Bu sanal makineyle ilişkili kimlik bilgileriniz (gcloud auth list
çalıştırıldığında gösterildiği şekilde), otomatik olarak Application Default Credentials (ADC) (Uygulama Varsayılan Kimlik Bilgileri) (ADC) tarafından kullanılacağından gcloud auth application-default login
komutunu kullanmanız gerekmez. Bununla birlikte, kimliğinizin Datastore Kullanıcısı rolüne sahip olması gerekir. Uygulamayı yerel olarak çalıştırma bölümüne geçebilirsiniz.
Ancak yerel terminalinizde (ör. Cloud Shell'de değil) çalışıyorsanız Google API'lerinde kimlik doğrulamak için Uygulama Varsayılan Kimlik Bilgilerini kullanmanız gerekir. 1) Kimlik bilgilerinizi kullanarak giriş yapabilirsiniz (Datastore Kullanıcısı rolüne sahipseniz) veya 2) bu codelab'de kullanılan hizmet hesabının kimliğine bürünerek giriş yapabilirsiniz.
1. Seçenek) ADC için kimlik bilgilerinizi kullanma
Kimlik bilgilerinizi kullanmak istiyorsanız gcloud'da kimlik doğrulamanın nasıl yapıldığını doğrulamak için önce gcloud auth list
komutunu çalıştırabilirsiniz. Ardından, kimliğinize Vertex AI Kullanıcısı rolünü vermeniz gerekebilir. Kimliğiniz Sahip rolüne sahipse bu Datastore Kullanıcısı kullanıcı rolüne zaten sahipsiniz demektir. Aksi takdirde, kimliğinize Vertex AI kullanıcı rolünü ve Datastore Kullanıcısı rolünü vermek için bu komutu çalıştırabilirsiniz.
USER=<YOUR_PRINCIPAL_EMAIL> gcloud projects add-iam-policy-binding $PROJECT_ID \ --member user:$USER \ --role=roles/datastore.user
Ardından aşağıdaki komutu çalıştırın
gcloud auth application-default login
2. Seçenek) ADC için Bir Hizmet Hesabının Kimliğine Bürünme
Bu codelab'de oluşturulan hizmet hesabını kullanmak istiyorsanız kullanıcı hesabınızın Hizmet Hesabı Jetonu Oluşturucu rolüne sahip olması gerekir. Bu rolü almak için şu komutu çalıştırın:
gcloud projects add-iam-policy-binding $PROJECT_ID \ --member user:$USER \ --role=roles/iam.serviceAccountTokenCreator
Ardından, ADC'yi hizmet hesabıyla kullanmak için aşağıdaki komutu çalıştıracaksınız
gcloud auth application-default login --impersonate-service-account=$SERVICE_ACCOUNT_ADDRESS
Uygulamayı yerel olarak çalıştırma
Ardından, codelab'iniz için cloud-run-github-cd-demo
kök dizininde olduğunuzdan emin olun.
cd .. && pwd
Şimdi bağımlılıkları yükleyeceksiniz.
npm install
Son olarak, aşağıdaki komut dosyasını çalıştırarak uygulamayı başlatabilirsiniz. Bu komut dosyası, tailwindCSS'den çıkış.css dosyasını da oluşturur.
npm run dev
Şimdi web tarayıcınızı açarak http://localhost:8080 adresine gidin. Cloud Shell'deyseniz Web Önizlemesi düğmesini açıp Önizleme Bağlantı Noktası 8080'i seçerek web sitesini açabilirsiniz.
Ad ve şehir giriş alanlarına metin girip Kaydet'e basın. Ardından sayfayı yenileyin. Kasaba alanının aktif olmadığını göreceksiniz. Bu hatayı sonraki bölümde düzelteceksiniz.
Ekspres uygulamanın yerel olarak çalışmasını durdurun (ör. MacOS'te Ctrl^c).
8. GitHub Deposu Oluştur
Yerel dizininizde varsayılan dal adı ana olan yeni bir depo oluşturun.
git init git branch -M main
Hatayı içeren mevcut kod tabanını taahhüt edin. Sürekli dağıtım yapılandırıldıktan sonra hatayı düzeltirsiniz.
git add . git commit -m "first commit for express application"
GitHub'a gidin ve size özel veya herkese açık olan boş bir depo oluşturun. Bu codelab'de, deponuz cloud-run-auto-deploy-codelab
olarak adlandırılabilir. Boş bir depo oluşturmak için varsayılan ayarların tümünü işaretlenmemiş olarak bırakır veya hiç içerik olmamasını sağlarsınız. Böylece, oluşturulan içerikler varsayılan olarak depoda yer almaz (ör.
Bu adımı doğru bir şekilde tamamladıysanız boş depo sayfasında aşağıdaki talimatları göreceksiniz:
Şu komutları çalıştırarak mevcut bir depoyu komut satırından aktarma talimatlarını uygulayın:
Öncelikle şu komutu çalıştırarak uzak depoyu ekleyin:
git remote add origin <YOUR-REPO-URL-PER-GITHUB-INSTRUCTIONS>
ana dalı yukarı akış deposuna aktarın.
git push -u origin main
9. Sürekli Dağıtımı Ayarla
Artık bir GitHub'da kodunuz olduğuna göre sürekli dağıtım oluşturabilirsiniz. Cloud Run için Cloud Console'a gidin.
- Hizmet Oluştur'u tıklayın.
- Repository'den sürekli olarak dağıt'ı tıklayın
- CLOUD BUILD'I KUR'u tıklayın.
- kod deposu altında
- Kod Deposu Sağlayıcı olarak GitHub'ı seçin
- Depoya Cloud Build erişimini yapılandırmak için Bağlı depoları yönet'i tıklayın.
- Deponuzu seçip Next'i (İleri) tıklayın
- Derleme Yapılandırması Altında
- Şubeyi ^main$ olarak bırak
- Derleme Türü için Google Cloud'un derleme paketleri aracılığıyla Go, Node.js, Python, Java, .NET Core, Ruby veya PHP'yi seçin
- Derleme bağlamı dizinini
/
olarak bırakın - Kaydet'i tıklayın
- Kimlik Doğrulama altında
- Kimliği doğrulanmayan çağrılara izin ver'i tıklayın
- Kapsayıcılar, Birimler, Ağ İletişimi, Güvenlik'in altında
- Güvenlik sekmesinin altında, önceki bir adımda oluşturduğunuz hizmet hesabını seçin (ör.
Cloud Run access to Firestore
.
- Güvenlik sekmesinin altında, önceki bir adımda oluşturduğunuz hizmet hesabını seçin (ör.
- OLUŞTUR'u tıklayın.
Bu işlem, bir sonraki bölümde düzelteceğiniz hatayı içeren Cloud Run hizmetini dağıtacaktır.
10. Hatayı düzelt
Koddaki hatayı düzeltin
Cloud Shell Düzenleyici'de app.js
dosyasını açın ve //TODO: fix this bug
yazan yoruma gidin.
aşağıdaki satırı şununla değiştir:
//TODO: fix this bug await doc.set({ name: name });
-
//fixed town bug await doc.set({ name: name, town: town });
Düzeltmeyi doğrulamak için
npm run start
web tarayıcınızı açın. Verileri yeniden şehir için kaydedin ve yenileyin. Yeni girilen şehir verilerinin, yenileme sonrasında doğru şekilde korunduğunu görürsünüz.
Düzeltmenizi doğruladığınıza göre, artık dağıtıma hazırsınız. Önce düzeltmeyi uygulayın.
git add . git commit -m "fixed town bug"
ve GitHub'daki yukarı akış deposuna aktarıyorum.
git push origin main
Cloud Build, değişikliklerinizi otomatik olarak dağıtır. Dağıtım değişikliklerini izlemek için Cloud Run hizmetinize ait Cloud Console'a gidebilirsiniz.
Üretimde düzeltmeyi doğrulayın
Cloud Run hizmetinizin Cloud Console'u gösterdiğinde ikinci bir düzeltme şu anda% 100 trafik sunuyor (ör. https://console.cloud.google.com/run/detail/<YOUR_REGION>/<YOUR_SERVICE_NAME>/revisions tarayıcınızda Cloud Run hizmet URL'sini açabilir ve sayfayı yeniledikten sonra yeni girilen şehir verilerinin silinmediğini doğrulayabilirsiniz.
11. Tebrikler!
Tebrikler, codelab'i tamamladınız.
Cloud Run ve git'ten sürekli dağıtım belgelerini incelemenizi öneririz.
İşlediklerimiz
- Cloud Shell Düzenleyici ile Express web uygulaması yazma
- Sürekli dağıtımlar için GitHub hesabınızı Google Cloud'a bağlayın
- Uygulamanızı otomatik olarak Cloud Run'a dağıtma
- HTMX ve TailwindCSS'yi nasıl kullanacağınızı öğrenin
12. Temizleme
Yanlışlıkla yapılan ücretleri önlemek için (örneğin, Cloud Run hizmetleri yanlışlıkla ücretsiz katmandaki aylık Cloud Run çağırma tahsisinizden daha fazla kez çağrıldıysa) Cloud Run'ı silebilir veya 2. adımda oluşturduğunuz projeyi silebilirsiniz.
Cloud Run hizmetini silmek için https://console.cloud.google.com/run adresinden Cloud Run Cloud Console'a gidin ve bu codelab'de oluşturduğunuz Cloud Run hizmetini silin (ör. cloud-run-auto-deploy-codelab
hizmetini silin.
Projenin tamamını silmeyi tercih ederseniz https://console.cloud.google.com/cloud-resource-manager adresine gidip 2. adımda oluşturduğunuz projeyi, ardından Sil'i seçebilirsiniz. Projeyi silerseniz Cloud SDK'nızdaki projeleri değiştirmeniz gerekir. gcloud projects list
komutunu çalıştırarak mevcut tüm projelerin listesini görüntüleyebilirsiniz.