การย้ายข้อมูลจากแอป Java ของ Google App Engine ไปยัง Cloud Run ด้วย Jib

1. ภาพรวม

ชุดโค้ดแล็บ (บทแนะนำแบบฝึกหัดด้วยตนเอง) นี้มีจุดประสงค์เพื่อช่วยให้นักพัฒนาซอฟต์แวร์ Java ของ Google App Engine (มาตรฐาน) ปรับแอปให้ทันสมัยโดยแนะนำขั้นตอนการย้ายข้อมูล เมื่อทำตามขั้นตอนเหล่านี้ คุณจะอัปเดตแอปให้พกพาได้มากขึ้นและตัดสินใจที่จะใช้คอนเทนเนอร์สำหรับ Cloud Run ซึ่งเป็นบริการโฮสติ้งคอนเทนเนอร์ของ Google Cloud ที่ทำงานร่วมกับ App Engine และบริการโฮสติ้งคอนเทนเนอร์อื่นๆ ได้

บทแนะนำนี้จะสอนวิธีสร้างคอนเทนเนอร์แอป App Engine สำหรับการทำให้ใช้งานได้กับบริการที่มีการจัดการครบวงจรของ Cloud Run โดยใช้ Jib Jib ช่วยให้คุณสร้างอิมเมจ Docker ซึ่งเป็นแพลตฟอร์มที่รู้จักกันดีในอุตสาหกรรมสำหรับการพัฒนา การจัดส่ง และเรียกใช้แอปพลิเคชันในคอนเทนเนอร์

นอกเหนือจากการสอนขั้นตอนที่จำเป็นในการย้ายจาก App Engine ไปยัง Cloud Run แล้ว คุณยังจะได้เรียนรู้วิธีอัปเกรดแอป Java 8 App Engine เป็น Java 17

หากแอปพลิเคชันของคุณใช้บริการแบบแพ็กเกจเดิมของ App Engine หรือฟีเจอร์อื่นๆ ของ App Engine เป็นจำนวนมาก เราขอแนะนำให้ย้ายข้อมูลออกจากบริการแบบแพ็กเกจเหล่านั้นหรือแทนที่ฟีเจอร์เหล่านั้นก่อนเปลี่ยนไปใช้ Cloud Run หากต้องการเวลาเพิ่มเติมในการตรวจสอบตัวเลือกการย้ายข้อมูลหรือต้องการใช้บริการแบบกลุ่มเดิมต่อไปในขณะนี้ คุณจะเข้าถึงบริการแบบกลุ่มของ App Engine สำหรับ Java 11/17 ได้ต่อไปเมื่ออัปเกรดเป็นรันไทม์ที่ใหม่กว่า เมื่อแอปของคุณเป็นแบบพกพาได้มากขึ้นแล้ว ให้กลับมาที่ Codelab นี้เพื่อดูวิธีใช้วิธีการกับแอป

คุณจะได้เรียนรู้วิธีต่อไปนี้

  • ใช้ Cloud Shell
  • เปิดใช้ Cloud Run, Artifact Registry และ Cloud Build API
  • สร้างคอนเทนเนอร์ให้กับแอปโดยใช้ Jib และ Cloud Build
  • ทำให้อิมเมจคอนเทนเนอร์ใช้งานได้กับ Cloud Run

สิ่งที่ต้องมี

แบบสำรวจ

คุณจะใช้บทแนะนำนี้อย่างไร

อ่านอย่างเดียว อ่านและทำแบบฝึกหัดให้เสร็จ

คุณจะให้คะแนนประสบการณ์การใช้งาน Java เท่าไร

มือใหม่ ระดับกลาง เชี่ยวชาญ

คุณจะให้คะแนนประสบการณ์การใช้งานบริการ Google Cloud เท่าใด

มือใหม่ ระดับกลาง เชี่ยวชาญ

2. ข้อมูลเบื้องต้น

ระบบแพลตฟอร์มในฐานะบริการ (PaaS) เช่น App Engine และ Cloud Functions มอบความสะดวกมากมายให้กับทีมและแอปพลิเคชันของคุณ เช่น ช่วยให้ผู้ดูแลระบบและนักพัฒนาซอฟต์แวร์สามารถมุ่งเน้นที่การสร้างโซลูชันได้ เมื่อใช้แพลตฟอร์มแบบเซิร์ฟเวอร์เสมือน แอปจะปรับขนาดอัตโนมัติได้ตามต้องการ ปรับขนาดลงเป็น 0 ด้วยการเรียกเก็บเงินแบบจ่ายต่อการใช้งานเพื่อช่วยควบคุมค่าใช้จ่าย และใช้ภาษาการพัฒนาทั่วไปที่หลากหลาย

อย่างไรก็ตาม ความยืดหยุ่นของคอนเทนเนอร์ก็น่าสนใจเช่นกัน ความสามารถในการเลือกภาษา ไลบรารี และไบนารีใดก็ได้ทำให้คอนเทนเนอร์เป็นแพลตฟอร์มที่ให้คุณได้รับสิ่งที่ดีที่สุดจากทั้ง 2 โลก ทั้งความสะดวกของการใช้งานแบบเซิร์ฟเวอร์เลสและความยืดหยุ่นของคอนเทนเนอร์ Cloud Run สร้างขึ้นเพื่อวัตถุประสงค์นี้

การเรียนรู้วิธีใช้ Cloud Run ไม่ได้อยู่ในขอบเขตของ Codelab นี้ ซึ่งอยู่ในเอกสารประกอบ Cloud Run เป้าหมายของเราคือช่วยให้คุณคุ้นเคยกับวิธีบรรจุคอนเทนเนอร์แอป App Engine สำหรับ Cloud Run (หรือบริการอื่นๆ ที่โฮสต์คอนเทนเนอร์) โปรดทราบว่าคุณควรทราบข้อมูลบางอย่างก่อนดำเนินการต่อ โดยเฉพาะอย่างยิ่งประสบการณ์ของผู้ใช้จะแตกต่างกันเล็กน้อย

ในโค้ดแล็บนี้ คุณจะได้เรียนรู้วิธีสร้างและทำให้คอนเทนเนอร์ใช้งานได้ โดยคุณจะได้เรียนรู้วิธีต่อไปนี้

  • สร้างคอนเทนเนอร์สำหรับแอปด้วย Jib
  • ย้ายข้อมูลออกจากการกำหนดค่า App Engine
  • และกำหนดขั้นตอนบิลด์สำหรับ Cloud Build หรือไม่ก็ได้

ซึ่งจะเกี่ยวข้องกับการเลิกใช้งานฟีเจอร์บางอย่างของ App Engine หากไม่ต้องการอัปเกรดตามเส้นทางนี้ คุณจะยังอัปเกรดเป็นรันไทม์ Java 11/17 ได้ขณะที่เก็บแอปไว้ใน App Engine แทน

3. การตั้งค่า/การเตรียมงาน

1. ตั้งค่าโปรเจ็กต์

ในบทแนะนำนี้ คุณจะใช้แอปตัวอย่างจากที่เก็บข้อมูล appengine-java-migration-samples ในโปรเจ็กต์ใหม่เอี่ยม ตรวจสอบว่าโปรเจ็กต์มีบัญชีสำหรับการเรียกเก็บเงินที่ใช้งานอยู่

หากต้องการย้ายแอป App Engine ที่มีอยู่ไปยัง Cloud Run คุณสามารถใช้แอปนั้นเพื่อทําตามแทน

เรียกใช้คำสั่งต่อไปนี้เพื่อเปิดใช้ API ที่จำเป็นสำหรับโปรเจ็กต์ของคุณ

gcloud services enable artifactregistry.googleapis.com cloudbuild.googleapis.com run.googleapis.com

2. รับแอปตัวอย่างพื้นฐาน

โคลนแอปตัวอย่างในเครื่องของคุณเองหรือใน Cloud Shell จากนั้นไปที่โฟลเดอร์ baseline

ตัวอย่างนี้เป็นแอป Datastore ที่ใช้ Servlet ของ Java 8 ซึ่งมีไว้เพื่อทำให้ใช้งานได้บน App Engine ทำตามวิธีการใน README เกี่ยวกับวิธีเตรียมแอปนี้สำหรับการนำ App Engine ไปใช้งาน

3. (ไม่บังคับ) ติดตั้งใช้งานแอปพื้นฐาน

ขั้นตอนต่อไปนี้จำเป็นเฉพาะในกรณีที่คุณต้องการยืนยันว่าแอปทำงานบน App Engine ได้ก่อนที่จะย้ายข้อมูลไปยัง Cloud Run

โปรดดูขั้นตอนใน README.md

  1. ติดตั้ง/ทบทวนการใช้ gcloud CLI
  2. เริ่มต้น gcloud CLI สำหรับโปรเจ็กต์ของคุณด้วย gcloud init
  3. สร้างโปรเจ็กต์ App Engine ด้วย gcloud app create
  4. ทำให้แอปตัวอย่างใช้งานได้ใน App Engine
./mvnw package appengine:deploy -Dapp.projectId=$PROJECT_ID
  1. ยืนยันว่าแอปทำงานบน App Engine โดยไม่มีปัญหา

4. สร้างที่เก็บ Artifact Registry

หลังจากบรรจุคอนเทนเนอร์แอปแล้ว คุณจะต้องมีที่สำหรับพุชและจัดเก็บรูปภาพ วิธีที่เราแนะนำใน Google Cloud คือการใช้ Artifact Registry

สร้างที่เก็บชื่อ migration ด้วย gcloud ดังนี้

gcloud artifacts repositories create migration --repository-format=docker \
--description="Docker repository for the migrated app" \
--location="northamerica-northeast1"

โปรดทราบว่าที่เก็บนี้ใช้ประเภทรูปแบบ docker แต่มีประเภทที่เก็บหลายประเภท

ตอนนี้คุณมีแอป App Engine พื้นฐานและโปรเจ็กต์ Google Cloud พร้อมที่จะย้ายข้อมูลไปยัง Cloud Run แล้ว

4. แก้ไขไฟล์แอปพลิเคชัน

ในกรณีที่แอปของคุณใช้งานบริการที่รวมอยู่ในแพ็กเกจ การกำหนดค่า หรือฟีเจอร์อื่นๆ ของ App Engine แบบเดิมมากเกินไป เราขอแนะนำให้เข้าถึงบริการเหล่านั้นต่อไปขณะที่อัปเกรดเป็นรันไทม์ใหม่ Codelab นี้จะสาธิตเส้นทางการย้ายข้อมูลสำหรับแอปพลิเคชันที่ใช้บริการแบบสแตนด์อโลนอยู่แล้ว หรืออาจเปลี่ยนโครงสร้างภายในโค้ดเพื่อดำเนินการดังกล่าวได้

1. การอัปเกรดเป็น Java 17

หากแอปใช้ Java 8 ให้พิจารณาอัปเกรดเป็น LTS รุ่นถัดไป เช่น 11 หรือ 17 เพื่อให้ทันการอัปเดตความปลอดภัยและรับสิทธิ์เข้าถึงฟีเจอร์ภาษาใหม่ๆ

เริ่มต้นด้วยการอัปเดตพร็อพเพอร์ตี้ใน pom.xml ให้รวมข้อมูลต่อไปนี้

<properties>
    <java.version>17</java.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
</properties>

การดำเนินการนี้จะตั้งค่าเวอร์ชันของโปรเจ็กต์เป็น 17 ให้แจ้งปลั๊กอินคอมไพเลอร์ว่าคุณต้องการเข้าถึงฟีเจอร์ภาษา Java 17 และต้องการให้คลาสที่คอมไพล์ดังกล่าวใช้งานได้กับ Java 17 JVM

2. รวมถึงเว็บเซิร์ฟเวอร์

App Engine และ Cloud Run มีความแตกต่างกันหลายอย่างที่ควรพิจารณาเมื่อย้ายระหว่าง App Engine กับ Cloud Run ความแตกต่างอย่างหนึ่งคือ ในขณะที่รันไทม์ Java 8 ของ App Engine จัดหาและจัดการเซิร์ฟเวอร์ Jetty สําหรับแอปที่โฮสต์ แต่ Cloud Run ไม่ได้ดำเนินการดังกล่าว เราจะใช้ Spring Boot เพื่อจัดหาเว็บเซิร์ฟเวอร์และคอนเทนเนอร์เซิร์ฟเลต

เพิ่มการพึ่งพาต่อไปนี้

<dependencies>
<!-- ... -->
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
       <version>2.6.6</version>
       <exclusions>
           <!-- Exclude the Tomcat dependency -->
           <exclusion>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-tomcat</artifactId>
           </exclusion>
       </exclusions>
   </dependency>
   <!-- Use Jetty instead -->
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-jetty</artifactId>
       <version>2.6.6</version>
   </dependency>
<!-- ... -->
</dependencies>

Spring Boot จะฝังเซิร์ฟเวอร์ Tomcat โดยค่าเริ่มต้น แต่ตัวอย่างนี้จะยกเว้นอาร์ติแฟกต์นั้นและใช้ Jetty ต่อไปเพื่อลดความแตกต่างของลักษณะการทำงานเริ่มต้นหลังการย้ายข้อมูล นอกจากนี้เรายังกำหนดค่าเวอร์ชัน Jetty ให้จับคู่กับเวอร์ชันใน App Engine ให้พร้อมใช้งานได้ทันที

<properties>
    <java.version>17</java.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <jetty.version>9.4.46.v20220331</jetty.version>
</properties>

3. การตั้งค่า Spring Boot

แม้ว่า Spring Boot จะใช้เซิร์ฟเล็ตซ้ำได้โดยไม่ต้องแก้ไข แต่จะต้องกำหนดค่าบางอย่างเพื่อให้ค้นพบได้

สร้างคลาส MigratedServletApplication.java ต่อไปนี้ในแพ็กเกจ com.example.appengine

package com.example.appengine;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@ServletComponentScan
@SpringBootApplication
@EnableAutoConfiguration
public class MigratedServletApplication {
    public static void main(String[] args) {
        SpringApplication.run(MigratedServletApplication.class, args);
    }
}

โปรดทราบว่าส่วนนี้รวมถึงคำอธิบายประกอบ @ServletComponentScan ซึ่งจะมีลักษณะ (ในแพ็กเกจปัจจุบันโดยค่าเริ่มต้น) สำหรับ @WebServlets ทั้งหมดและทำให้พร้อมใช้งานตามที่คาดไว้

4. การแพ็กเกจแอปเป็น JAR

แม้ว่าคุณจะจัดคอนเทนเนอร์แอปด้วย Jib ได้โดยเริ่มจาก war แต่การแพ็กเกจแอปเป็น JAR ที่เรียกใช้ได้จะง่ายกว่า ซึ่งไม่จำเป็นต้องมีการกําหนดค่ามากนัก โดยเฉพาะสําหรับโปรเจ็กต์ที่ใช้ Maven เป็นเครื่องมือสร้าง เนื่องจากการบรรจุ JAR เป็นลักษณะการทํางานเริ่มต้น

นำแท็ก packaging ในไฟล์ pom.xml ออกโดยทำดังนี้

<packaging>war</packaging>

ถัดไป ให้เพิ่ม spring-boot-maven-plugin

<plugins>
<!-- ... -->
  <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <version>2.6.6</version>
  </plugin>
<!-- ... -->
</plugins>

5. การย้ายข้อมูลจากการกำหนดค่า บริการ และทรัพยากร Dependency ของ App Engine

ดังที่ได้กล่าวไว้ในตอนต้นของโค้ดแล็บว่า Cloud Run และ App Engine ออกแบบมาเพื่อมอบประสบการณ์การใช้งานที่แตกต่างกัน ฟีเจอร์บางอย่างที่ App Engine มีให้ใช้งานโดยค่าเริ่มต้น เช่น บริการ Cron และ Task Queue จะต้องสร้างใหม่ด้วยตนเองและเราจะอธิบายรายละเอียดเพิ่มเติมในโมดูลต่อๆ ไป

แอปตัวอย่างไม่ได้ใช้บริการแบบรวมเดิม แต่ผู้ใช้ที่แอปใช้บริการแบบรวมเดิมสามารถดูคำแนะนำต่อไปนี้

เนื่องจากคุณจะทำให้ใช้งานได้กับ Cloud Run นับจากนี้ไป คุณจึงสามารถนำ appengine-maven-plugin ออกได้

<plugin>
 <groupId>com.google.cloud.tools</groupId>
 <artifactId>appengine-maven-plugin</artifactId>
 <version>2.4.1</version>
 <configuration>
   <!-- can be set w/ -DprojectId=myProjectId on command line -->
   <projectId>${app.projectId}</projectId>
   <!-- set the GAE version or use "GCLOUD_CONFIG" for an autogenerated GAE version -->
   <version>GCLOUD_CONFIG</version>
 </configuration>
</plugin>

5. คอนเทนเนอร์แอปพลิเคชัน

ตอนนี้คุณสามารถทำให้แอปใช้งานได้ใน Cloud Run ด้วยตนเองโดยตรงจากซอร์สโค้ด ตัวเลือกนี้เป็นตัวเลือกที่ยอดเยี่ยมซึ่งใช้ Cloud Build ทำงานเบื้องหลังเพื่อให้คุณไม่ต้องดำเนินการใดๆ เราจะอธิบายรายละเอียดเพิ่มเติมเกี่ยวกับการทําให้แหล่งที่มาใช้งานได้ในโมดูลต่อๆ ไป

หรือหากต้องการควบคุมวิธีทำให้แอปใช้งานได้มากขึ้น คุณก็ทำได้ด้วยการกําหนดไฟล์ cloudbuild.yaml ที่แสดงขั้นตอนการสร้างที่ต้องการอย่างชัดเจน ดังนี้

1. กำหนดไฟล์ cloudbuild.yaml

สร้างไฟล์ cloudbuild.yaml ต่อไปนี้ที่ระดับเดียวกับ pom.xml

steps:
  # Test your build
  - name: maven:eclipse-temurin
    entrypoint: mvn
    args: ["test"]
  # Build with Jib
  - name: maven:eclipse-temurin
    entrypoint: mvn
    args: [ "compile", "com.google.cloud.tools:jib-maven-plugin:3.2.1:build", "-Dimage=northamerica-northeast1-docker.pkg.dev/PROJECT_ID/migration/visitors:jib"]
  # Deploy to Cloud Run
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: gcloud
    args: [ 'run', 'deploy', 'visitors', '--image', 'northamerica-northeast1-docker.pkg.dev/PROJECT_ID/migration/visitors:jib', '--region', 'northamerica-northeast1', '--allow-unauthenticated']

เมื่อเราบอก Cloud Build ให้ทําตามขั้นตอนเหล่านี้แล้ว ระบบจะดำเนินการต่อไปนี้

  1. ทำการทดสอบด้วย ./mvnw test
  2. สร้าง พุช และติดแท็กรูปภาพไปยัง Artifact Registry ด้วย Jib
  3. ทำให้อิมเมจใช้งานได้ใน Cloud Run ด้วย gcloud run deploy

โปรดทราบว่า ‘visitors' จะเป็นชื่อบริการที่ส่งไปยัง Cloud Run Flag –allow-unauthenticated ช่วยให้ผู้ใช้เข้าชมเว็บแอปได้โดยไม่ต้องมีการตรวจสอบสิทธิ์ อย่าลืมแทนที่ PROJECT_ID ด้วยรหัสของโครงการในไฟล์ cloudbuild.yaml

จากนั้นเพิ่มการเชื่อมโยงนโยบาย IAM ต่อไปนี้เพื่ออนุญาตให้บัญชีบริการ Cloud Build เข้าถึงที่เก็บอาร์ติแฟกต์

export PROJECT_ID=$(gcloud config list --format 'value(core.project)')
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)" )

gcloud projects add-iam-policy-binding $PROJECT_ID \
--member=serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com \
--role=roles/run.admin \
--project=$PROJECT_ID
gcloud iam service-accounts add-iam-policy-binding $PROJECT_NUMBER-compute@developer.gserviceaccount.com \
--member=serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com \
--role roles/iam.serviceAccountUser --project=$PROJECT_ID

2. เรียกใช้กระบวนการบิลด์

เมื่อแจ้ง Cloud Build เกี่ยวกับขั้นตอนบิลด์ที่ต้องการแล้ว คุณก็พร้อมติดตั้งใช้งานได้ในคลิกเดียว

เรียกใช้คำสั่งต่อไปนี้

gcloud builds submit

เมื่อกระบวนการเสร็จสิ้นแล้ว ระบบจะสร้างอิมเมจคอนเทนเนอร์ จัดเก็บไว้ใน Artifact Registry และทำให้ใช้งานได้ใน Cloud Run

เมื่อจบ Codelab นี้ แอปของคุณควรมีลักษณะเหมือนกับแอปใน java17-and-cloud-run/finish

เพียงเท่านี้ก็เรียบร้อยแล้ว คุณได้ย้ายข้อมูลแอป App Engine เวอร์ชัน Java 8 ไปยัง Java 17 และ Cloud Run เรียบร้อยแล้ว และตอนนี้คุณเข้าใจงานที่เกี่ยวข้องเมื่อเปลี่ยนและเลือกระหว่างตัวเลือกโฮสติ้งได้ชัดเจนขึ้น

6. สรุป/ล้างข้อมูล

ยินดีด้วย คุณได้อัปเกรด ใส่คอนเทนเนอร์ ย้ายข้อมูล และอัปเดตแอปแล้ว ซึ่งถือเป็นการสิ้นสุดบทแนะนำนี้

จากขั้นตอนนี้ ขั้นตอนถัดไปคือดูข้อมูลเพิ่มเติมเกี่ยวกับฟีเจอร์ความปลอดภัยของ CI/CD และซัพพลายเชนซอฟต์แวร์ที่คุณใช้งานได้แล้วตอนนี้เมื่อใช้ Cloud Build

ไม่บังคับ: ล้างข้อมูลและ/หรือปิดใช้บริการ

หากคุณทำให้แอปตัวอย่างใช้งานได้ใน App Engine ระหว่างบทแนะนำนี้ อย่าลืมปิดใช้แอปเพื่อหลีกเลี่ยงการเรียกเก็บเงิน เมื่อพร้อมที่จะไปยังโค้ดแล็บถัดไป คุณจะเปิดใช้โค้ดแล็บอีกครั้งได้ เมื่อปิดใช้แอป App Engine ระบบจะไม่เรียกเก็บเงินสำหรับการเข้าชมแอปดังกล่าว แต่อาจเรียกเก็บเงินสำหรับการใช้งาน Datastore หากเกินโควต้าแบบไม่มีค่าใช้จ่าย ดังนั้นให้ลบข้อมูลให้เหลือไม่เกินขีดจำกัดดังกล่าว

ในทางกลับกัน หากไม่ต้องการย้ายข้อมูลต่อและต้องการลบทุกอย่างออกอย่างสมบูรณ์ คุณสามารถลบบริการหรือปิดโปรเจ็กต์ทั้งหมด

7. แหล่งข้อมูลเพิ่มเติม

ปัญหา/ความคิดเห็นเกี่ยวกับ Codelab ของโมดูลการย้ายข้อมูล App Engine

หากมีปัญหาใดๆ เกี่ยวกับ Codelab นี้ โปรดค้นหาปัญหาของคุณก่อนยื่น ลิงก์สำหรับค้นหาและสร้างปัญหาใหม่

แหล่งข้อมูลการย้ายข้อมูล

แหล่งข้อมูลออนไลน์

ด้านล่างนี้คือแหล่งข้อมูลออนไลน์ที่อาจเกี่ยวข้องกับบทแนะนำนี้

App Engine

ข้อมูลอื่นๆ เกี่ยวกับระบบคลาวด์

วิดีโอ

ใบอนุญาต

ผลงานนี้ได้รับอนุญาตภายใต้สัญญาอนุญาตครีเอทีฟคอมมอนส์สำหรับยอมรับสิทธิของผู้สร้าง (Creative Commons Attribution License) 2.0 ทั่วไป