สร้าง Soft(ware) Power ด้วย Backstage

Watchanon Numnam
7 min readDec 28, 2023

เนื้อหานี้เป็นส่วนหนึ่งของซีรีย์ IDP และทีม โดยจะพยายามทำให้เห็นไอเดียว่าสิ่งนี้น่าจะเข้ามาช่วยอะไรได้บ้างโดยไม่ลงรายละเอียดแต่จะพยายามให้ลิ้งไปอ่านเพิ่มเติมกันเอาเองให้มากที่สุด

source https://backstage.io/blog/2020/03/18/what-is-backstage/

ตอนที่ 3 สร้าง Soft(ware) Power ด้วย Backstage

ความเดิมตอนที่แล้ว ด้วยการที่ทีมมีการทำงานที่ค่อยข้างจะแตกต่างกับทีมอื่นๆ เป้าหมายของทีม ณ ตอนแรกน้ันอาจจะไม่เหมือนกัน และด้วยเวลาในการทำงานที่อาจจะไม่สอดคล้องกัน บ่อยครั้งเราเลยจำเป็นจะต้องทำ Service อะไรที่แต่ละทีมจำเป็นต้องใช้กันไปก่อนโดยที่อาจจะไม่รู้เลยว่าสิ่งนั้นมีอยู่ใน Core Platform อยู่แล้วหรือไม่ หรือบางทีก็อาจจะไม่มี Platform team อยู่จริงๆ เราเลยจึงคิดว่าถ้ามันเอา Backstage มาทำเป็น Software Catalog ขององค์กรแล้วทำให้เกิดการแชร์ข้อมูลกันระหว่างทีมต่างๆจะได้เห็นภาพใหญ่ของทั้งองค์กร หรือเห็นข้อมูลของแต่ละทีม เพื่อสร้าง Shared Understanding ก็น่าจะดี แล้ว Backstage มันทำอะไรได้บ้าง มันมีฟีเจอร์อะไรที่เราเอามาใช้บ้างหละ ลองมาทำความรู้จักกัน

Backstage

Backstage เป็น An open platform for building developer portals โดยตัวมันถูกเขียนมาด้วยภาษา NodeJS และ UI เขียนด้วย React แต่ก็มีการเรียกใช้คำสั่ง Native ของโปรแกรมอื่นๆผ่านทาง Python บ้าง โดยตัวเวปของมันจะมีลักษณะเป็นโครงของโปรแกรมและมีส่วนฟีเจอร์ต่างๆมาเป็นรูปแบบของ Plugins โดยที่จะมี Build-in Plugin มาให้อยู่แล้วตั่งแต่ตอนติดตั่ง และพวก 3rd Party Plugin หรือเราก็สามารถเขียน Plugin เพื่อเพิ่มความสามารถเข้าไป วิธีการลงสามารถไปดูกันเอาเองได้ที่ลิ้ง https://backstage.io/docs/getting-started/

โดยทีมใช้ Plugin ให้ Authentication ผ่าน Gitlab และให้สิทธิ์ให้มันเข้าถึงทุก Repo ของเราได้ เพื่อให้มัน Scan หาไฟล์ catalog-info.yaml ที่อยู่ในแต่ละ Repo ซึ่งไฟล์ catalog-info.yaml นี้เป็น Declarative ของ Backstage แต่ก็ยังสามารถใช้วิธี Manual เพิ่ม Repo เข้าไปได้

Core Feature

Backstage จะมี Core Feature เป็น Software Catalog, Kubernetes, Software Templates, Backstage Search และ TechDocs แต่ในส่วนนี้จะขอลงรายละเอียดหลักๆเพียงไม่กี่ตัวละกันที่เป็นจุดที่เราคิดว่ามันน่าจะมาตอบโจทย์ของ IDP ของทีม

Software Catalog

source https://demo.backstage.io/catalog/default/component/artist-lookup

ในส่วนของ Software Catalog จะเป็นเสมือนทะเบียนของระบบที่เราทำขึ้นมาในองค์กร เมื่อเข้าไปแต่ละระบบจะสามารถแสดงเป็น System Model เพื่อแสดงความสัมพันธ์ของแต่ละระบบเอาไว้ โดยมีส่วนกระกอบหลักดังนี้

backstage software catalog core entities

Core Entities

  • Components คือชิ้นส่วนของ Software หนึ่งๆ
  • APIs คือ ส่วนขอบของแต่ละ Components ที่ใช้ติดต่อกัน (จริงๆก็ตามตัวคือ Interface หรือ API นั่นแหละ)
  • Resource คือ Physical หรือ Virtual infrastructure ที่ใช้ในการรัน Component นั้น

ขอยกตัวอย่างเรื่อง Upload รูปไปลง Bucket เหมือนเดิมละกัน File Upload Service คือ Component โดยมี Interface เป็น API ให้ POST รูปเข้ามา แล้วเราก็เอารูปไปเก็บใน Bucket และ Insert ลง Database ซึ่งคือ Resource

แต่ตัวมันเองก็ยังมี Entities อื่นๆเพื่อใช้อธิบายอะไรที่ใหญ่ขึ้นได้ในระดับองค์กรได้ก็คือ Organizational Entities เช่น User, Group, System, Domain แต่ในบทความนี้ขอไม่ลงลายละเอียด

backstage organization entities

สามารถดูตัวอย่างของ System Model เพิ่มเติมได้ที่ลิ้งนี้

file catalog-info.yaml in git repo

โดยการเขียนจะเป็นรูปแบบ YAML ในไฟล์ catalog-info.yaml ของแต่ละ Git Repository ซึ่งแต่ละทีมที่เป็นผู้ดูแลแต่ละระบบก็สามารถที่จะเพิ่มเข้าไปได้เอง

apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: artist-web
description: The place to be, for great artists
labels:
example.com/custom: custom_label_value
annotations:
example.com/service-discovery: artistweb
circleci.com/project-slug: github/example-org/artist-website
backstage.io/techdocs-ref: dir:.
tags:
- java
links:
- url: https://admin.example-org.com
title: Admin Dashboard
icon: dashboard
type: admin-dashboard
spec:
type: website
lifecycle: production
owner: artist-relations-team
system: public-websites
providesApis:
- artist-api

ตัวอย่างข้างบนคือการสร้าง artist-web Component โดยอยู่ภายใต้ System ที่ชื่อว่า public-websites และมีเจ้าของเป็นทีม artist-relation-teams และ Provider API ชื่อ artist-api และเราสามารถเขียนอธิบายให้ artist-api ได้เพิ่มเติมได้ด้วย swagger

apiVersion: backstage.io/v1alpha1
kind: API
metadata:
name: artist-api
description: The Artist API
spec:
type: openapi
lifecycle: production
owner: artist-relations-team
definition:
$text: ./swagger/swagger.yaml

หน้าจอของ Backstage แสดง Swagger UI ตามที่เรากำหนดไว้ ในตัวอย่างนี้จะบอกว่าไฟล์ swagger.yaml จะอยู่ใน Repo ใต้ Folder ชื่อ Swagger

โดยสามารถไปดูเพิ่มเติม Descriptor format ของ Catalog Entity ได้ที่นี่

จริงๆแล้วความสามารถของ Software Catalog ยังไม่หมด สามารถเพิ่ม Plugin อื่นๆเข้าไปอีกได้เรื่อยๆเพื่อแสดงหน้าจอเพิ่มเข้าไป ยกตัวอย่างที่ผมใช้ก็คือ ต่อเข้ากับ Gitlab-CI เพื่อแสดง Build ของแต่ละ Commit เข้ามา ต่อเข้ากับ Argo-CD เพื่อแสดง History ของการ Sync Argo-CD แต่ละ Environment โดยเราสามารถเพิ่ม Plugin และเพิ่มหน้าจอเข้าไปได้เลย

add more feature by adding new plugin

โดยที่ Software Catalog นั้นเป็นการ Shared Understanding ในมุมมองของ Relations ของระบบอธิบาย API แต่ถ้าจะลงให้เห็นรายละเอียดของระบบส่วนต่างๆทีมจำเป็นต้องเขียนเอกสารเพิ่มเติมเข้าไปเข้าไว้เป็น TechDocs คล้ายๆกับการที่เราเขียน README.MD

TechDocs

เป็นส่วนเสริมที่จะช่วยแปลงไฟล์เอกสารที่เราเขียนด้วย MkDocs เป็น html แล้วนำมาแสดงผลในหน้าจอ โดยเราสามารถระบุให้นำไฟล์ที่แปลงเป็น html แล้วไปเก็บที่ Storage ที่เรากำหนดได้เช่น local, S3 หรือ GCS

backstage techdocs

โดยเราสามารถเขียนรายละเอียดของงาน, วิธีการเซ็ตอัพโปรเจคในครั้งแรก, การติดตั่ง Pre-Push หรือ Pre-Commit, วิธีการโหลด Dependencies, ต้องขอสิทธิอะไรบ้างในการรัน หรืออะไรก็ได้ที่ทีมจำเป็นต้องรู้เพื่อให้เมื่อมีทีมอื่นๆเข้ามาดูจะได้เข้าใจรายละเอียดของงานเราให้มากที่สุด หรือเวลามีสมาชิกของทีมเราเข้ามาเพิ่มเค้าก็สามารถเข้ามาดูรายละเอียดและพร้อมที่จะทำงานต่อได้เลย หรือแม้กระทั้งเขียนยอกตัวเราเองในอนาคติ เมื่อต้องกลับมาดูงานชิ้นนี้ใหม่อีกรอบจะได้เข้าใจ และยังสามารถนำ Plugin ที่ช่วยแปลงไฟล์ PlantUML เป็น SVG ใส่เข้าไปเพื่อช่วยให้เราอธิบายงานต่างๆในรูปแบบของ Diagram ไม่ว่าจะเป็น Flow Diagram, Sequence Diagram ของ API เส้นต่างๆได้เลย

# This is document with embedded PlantUML

```plantuml
!include docs/assets/system-diagram.puml
```

จริงๆมันก็คล้ายกับการที่เราเขียน Markdown แล้วพวก Gitlab หรือ Github นำไปแสดงผลนั่นแหละ แค่ Backstage มันเปิดให้เรารวบรวมเอกสารเพื่อไปแสดงผลในที่เดียวกันให้หมด และเรา Custom มันเองได้

โดยการระบุว่าให้ Backstage ไปอ่านไฟล์ TechDocs จากที่ Folder ไหนจะทำที่ Kind Component โดยจะอยู่ใน annotations ที่ชื่อว่า “backstage.io/techdocs-ref” ตัวอย่างนี้เราใส่เป็น dir:. ก็คือ ภายใน Git Repo ของมันเอง ที่ Root folder จากนั้น Backstage จะไปอ่าน Default Folder ของ TechDocs ของมันซึ่งคือ “docs”

apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: artist-web
description: The place to be, for great artists
annotations:
backstage.io/techdocs-ref: dir:.
backstage techdocs

หรือลองเข้าไปดู Repo ของ Backstage ก็จะเห็นตัวอย่างที่เค้าใช้จริงของ หน้าเวป Demo

Architecture Decision Records (ADRs)

ส่วนสุดท้ายที่คิดว่าหลายๆทีมยังไม่มีแต่มันเป็นสิ่งที่ควรจะเขียนเพิ่มเข้าไปก็คือ Architecture Decision Records (ADRs) อันที่จริงมันก็เหมือน Logs ของการตัดสินใจของทีมพัฒนา “ณ วันนั้น” เราเลือกสิ่งนี้ไปเพราะอะไร ด้วยความต้องการอะไร หรือมีข้อจำกัดอะไร เพื่อสักวันหนึ่งในอนาคติคนที่เข้ามาอ่านจะได้ทำความเข้าใจว่าระบบที่เป็นอยู่มันเกิดการตัดสินใจอะไรมาแล้วบ้าง

เช่นทีมเลือกใช้ MySQL ณ ตอนนั้นเพราะไม่มีคนในในบริษัทสามารถดูแล Mongo ได้ ซึ่ง​ ณ วันนี้ ข้อจำกัดนี้อาจจะหายไปแล้ว มันอาจจะไม่ได้เป็น Constrain ตอนนี้ถ้าทีม ณ ตอนนี้ตัดสินใจว่ามีเทคโนโลยีใหม่ แล้วเราพร้อมจะดูแลมันได้แล้ว บ่อยครั้งผมมักพบว่า เมื่อเราไปอ่าน Code เก่าๆเรามักไม่เข้าใจเลยว่าทำไมเค้าถึงทำแบบนั้นแบบนี้ หลายครั้ง เราก็ไม่กล้าเปลี่ยนแปลงมันเพราะเราคิดว่ามันมีข้อกำหนดบางอย่างที่เราเปลี่ยนแปลงมันไม่ได้

สำหรับผม ส่วนของ TechDocs มันก็เหมือนกับเอกสารที่ปกติเราต้องทำอยู่แล้ว แต่เมื่อก่อนมันอาจจะอยู่ในรูปแบบอื่น แค่ทำให้มันอยู่ในรูปแบบของ MkDocs แล้วก็ Commit ลงใน Git แล้วก็ Config เพิ่มอีกนิดหน่อยให้มันสามารถเอามาแสดงผลใน Backstage คิดว่า Software Catalog และ TechDocs มันก็น่าจะเข้ามาช่วย Shared Understanding ของทีมต่างๆที่เข้ามาอ่านได้มากขึ้นแล้ว แต่ Backstage สำหรับผมในมุมมอง Dev และ DevOps มันยังมีบางอย่างที่น่าสนใจอีกในฟีเจอร์อย่าง Software Templates

Software Templates

ผมเชื่อว่าในบางทีม จะมีพี่ๆ Senior เขียน Code เป็นโปรเจคตั่งต้นเอาไว้ เมื่อต้องทำโปรเจคใหม่ๆก็จะเอาโปรเจคตั่งต้นนี้มา Checkout เอามาแก้ๆๆๆ Rename แล้ว Push เป็น Repo ใหม่เพื่อให้สามารถเริ่มได้อย่างรวดเร็วโดยไม่ต้องเริ่มต้นใหม่ทั้งหมด และใช่ครับ Software Template เกิดมาเพื่อสิ่งนี้!

backstage software template

เราสามารถสร้าง Repo เข้ามาเป็น Software Template ได้ด้วยการ เขียนไฟล์ catalog-info.yaml ประมาณนี้

apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
# some metadata about the template itself
metadata:
name: v1beta3-demo
title: Test Action template
description: scaffolder v1beta3 template demo
spec:
owner: backstage/techdocs-core
type: service

# these are the steps which are rendered in the frontend with the form input
parameters:
- title: Fill in some steps
required:
- name
properties:
name:
title: Name
type: string
description: Unique name of the component
ui:autofocus: true
ui:options:
rows: 5
- title: Choose a location
required:
- repoUrl
properties:
repoUrl:
title: Repository Location
type: string
ui:field: RepoUrlPicker
ui:options:
allowedHosts:
- github.com

# here's the steps that are executed in series in the scaffolder backend
steps:
- id: fetch-base
name: Fetch Base
action: fetch:template
input:
url: ./template
values:
name: ${{ parameters.name }}

- id: publish
name: Publish
action: publish:github
input:
allowedHosts: ['github.com']
description: This is ${{ parameters.name }}
repoUrl: ${{ parameters.repoUrl }}

ถ้าจะให้อธิบายคร่าวๆให้สังเกตตรงที่ Parameters และ Steps ละกันส่วนนี้เป็นส่วนสำคัญของการแสดงผลหน้าจอของ Backstage และกำหนดว่าให้มันทำอะไรบ้าง

Parameters

เป็นตัวกำหนดว่าจะให้หน้าจอของ Backstage แสดง Input อะไรบ้าง ในตัวอย่างนี้มี Parameter “Name” และ “Repository Location” เมื่อเราเลือกใช้ Template นี้จะมี TextField ให้เรากรอก Name และแสดง DropDown ให้เราเลือก Repository Location ที่มี option ให้เลือกแค่ github.com หรือเราจะเพิ่มเติมทำ CheckBox อะไรเข้าไปก็ได้ โดยเขียนเป็น Declarative ตาม Doc ได้เลย แล้ว Backstage จะทำการแสดงผลหน้าจอให้

Steps

เป็นลำดับขั้นตอนที่เราต้องการให้ Backstage ทำให้ จากตัวอย่างมี Step ดังนี้

1. fetch-base โดยเป็นการระบุให้ไฟล์ที่ Url ./template ของ Repo (คือ Folder template ใน repo) มารันด้วย Action fetch:template โดยกำหนดค่าตัวแปร name ของ action นี้ให้มาจากค่า parameters.name จากที่เรา Input เข้าไป

ผลก็คือ Backstage จะทำการ clone repo นี้มา แล้วเอา ไฟล์ทั้งหมดใน Folder /template มารันด้วย Go Template โดนใส่ค่า name = “Input Name” เข้าไป Code ส่วนไหนที่เราเจาะช่องให้แทนที่ค่าตัวแปร name ไว้ก็จะโดนแทนที่ค่าทันที

${{ values.name }}

2. Publish ซึ่งใช้ Action publish:github คือการสร้าง Commit แล้ว Push ไปยัง Repo ที่เรากำหนดไว้ใน repoUrl

จริงๆแล้ว Action ของมันมีหลายตัวมีบิ้วอินมาให้เบื้องต้นมีให้โหลดเพิ่มและเราก็สามารถเขียนเข้าไปเองได้

ลองไปดูเพิ่มเติมได้ที่

ตัวอย่างการเขียน Softwate Template

ถ้าจะให้พูดงานๆ Software Template ก็เหมือนกับการทำ Template string เอาไว้แล้วให้มันมารันเปลี่ยนค่าเป็นค่าต่างๆตามที่เราเจาะช่องเอาไว้ ดังนั้น string ทุกตัวที่อยู่ใน git ของเราก็จะโดนแทนที่ค่าได้

แต่เอ้!! นี้มัน

ยังจำได้ไหมครับใน EP1 ผมเคยบอกว่า วิธีการทำงานของทีมผมแปลกๆอย่างนึงคือ เราทำ mono repo ที่มีทั้ง source code มีทั้ง helm มีทั้ง terraform มีทั้ง Build Pipeline แล้วถ้าเอา Backstage software template มันทำ template ทั้งหมดจะเกิดอะไรขึ้นนะ

  • ปกติผมจะใช้ Kong Ingress เป็นตัวกำหนด Route เข้ามายัง Service ใน Kubernetes แล้วผมก็เขียนมันไว้ใน Helm แล้วถ้ามันเอาสิ่งนี้มาทำเป็น Template ไว้หละ
  • ถ้าผมทำ Checkbox ว่า Service นี้เอา Ingress ด้วยละ
  • ทีมเราพยายามเขียน Infra As Code เป็น Terraform อยู่ใน Project เอ้ถ้ามันเอามาทำเป็น Template ไว้หละ หรือว่ามันมีเครื่องมืออื่นที่ผมจะลดการเขียน Terraform แต่ผมยังใช้เขียน Infra แบบ Declarative ได้อยู่แต่เป็นการเขียน Helm แทนหละ
  • การขอสิทธิของ GCP ใน Project ของเราปกติเราใช้ Workload Identity โดนการลิ้ง Kubernetes Service Account เข้ากับ Google Service Account แล้วทำการเพิ่มสิทธิให้ Google Service Account ของเราโดยตัว Source code หรือ POD ไม่ต้องถือ secret เข้าไปเลย ถ้ากระบวนการพวกนี้สามารถเขียนเป็นแบบ Declarative แบบ Helm ได้หมดหละ แล้ว Software Teamplate ทำให้เราได้หละ
  • Build Pipeline หละ

เอ้แบบนี้ทุกอย่างที่เราเคยทำเป็น As Code มันสามารถใช้ Software Template ทำได้หมดเลยสินะ

ลองจินตนาการตามผมนิดนึงนะครับ ปกติเมื่อก่อนเราต้องทำอะไรบ้างเมื่อเริ่มต้น Service ใหม่ตัวนึง เราอาจจะเริ่มต้นจาก Clone Project ตัวอย่าง แล้วเอามาแก้ แล้วก็ Push เข้าไปที่ Repo ใหม่ จากนั้นเราอาจจะแก้ Build Pipeline ให้เปลี่ยนที่เก็บ Image เข้าไปแก้ เพิ่ม Config Argo-Cd เพื่อให้มัน Sync repo ใหม่ จากนั้นอาจจะไปขอสิทธิทีม Infra ขอ iam permission ในสิ่งต่างๆที่เราต้องการ เราทำการเพิ่ม Ingress mapping DNS ของแต่ละอย่างเข้ามาที่ service ของเรา หรือขอ DNS ใหม่

ถ้าทั้งหมดนี้มันโดนเขียนด้วยทีมของเราแบบ Declarative แล้วมันเกิดจากการที่เรากดเลือกใน Software template มาหละ

เมื่อเราต้องการ Project ใหม่จากเลือก Template Golang GIN แล้วติ๊กเลือกว่าเราจะสร้าง Ingress ชื่ออะไรแล้วให้มันสร้าง Ingress manifest มาให้เราเลย แล้วเราเลือกว่า Service ของเราต้องการ Permission อะไรบ้างเช่น cloudsql client เพื่อต่อ DB ได้ และเลือก cloud storage user เพื่ออ่านเขียน GCS ได้ แล้วเราก็เลือกว่าเราจะสร้าง GCS ชื่ออะไร แล้วให้มัน Generate Kubernetes Manifest ออกมาให้เราเลย แล้วกดแค่ OK

จากนั้น Backstage software template ก็จะสร้างทุกอย่างให้เราเกิดเป็น hello world service ที่มี pipeline วิ่งต่อไปยัง Production มี Resource และ Permssion ทุกอย่างที่ Project นี้ต้องการ แล้วก็มี URLให้เราเรียกใช้งานได้เลยหละ

ผมว่า Lead time จาก Idea จนถึง Production น่าจะลดลงไปมากเลย แล้ว Developer Experience น่าจะดีขึ้นมากๆ

อันนี้คือ Next step ที่ผมจะไป

เดี๋ยว Ep ต่อไปผมจะมาเล่าก้าวต่อไปว่าผมจะลดการเขียน Terraform มาเขียนเป็น Kubenetes manifest เพื่อให้ Stream-aligned team สามารถสร้าง Infra ได้โดยที่ Platform team ยังคง Governance มันได้อยู่ด้วย crossplane.io

--

--