python aks_使用环回aks和terraform构建基于打字稿的游戏后端
python aks
介紹 (Introduction)
This started as a summer side-project — build an online version of the popular Italian card game Scopa which I called the Scoparella project. Most importantly it was a chance to get hands-on with some technologies I’d been eager to explore in more depth, in particular Azure Kubernetes Service (AKS) and Loopback, a framework for building microservices with Typescript.
這項計劃最初是從一個夏季的附帶項目開始的-建立一個流行的意大利紙牌游戲Scopa的在線版本,我稱之為Scoparella項目 。 最重要的是,這是一個機會,可以親身體驗一些我渴望更深入探索的技術,尤其是Azure Kubernetes Service(AKS)和Loopback(使用Typescript構建微服務的框架)。
Scopa is a traditional Italian card game played with a 40-card deck of Italian cards (also playable with the more familiar 52-deck cards by removing the 8, 9 and 10s). The rules are fairly simple, and can be easily found on Google so I won’t digress here. To facilitate this I wrote an engine for the game in Typescript. The API for the engine library is fairly rudimentary:
Scopa是一種傳統的意大利紙牌游戲,使用40張紙牌的意大利紙牌(也可以通過移除8、9和10來與更熟悉的52層紙牌一起玩)。 這些規則非常簡單,可以在Google上輕松找到,因此我不會在這里討論。 為了方便起見,我用Typescript編寫了游戲的引擎 。 引擎庫的API相當初級:
const game = new ScoparellaGame({numberOfPlayers: 2});game.addPlayer(new ScoparellaPlayer("player1"));
game.addPlayer(new ScoparellaPlayer("player2"));
This sets up a game with 2 players…
設置了一個有2個玩家的游戲…
game.tryPlayCards(cardToPlay, cardsToTake, playersHand);…attempts to play a card and take 0…many cards, while playersHand indicates the player playing the hand. Validation is done under the hood to ensure any move is legal before committing it.
…嘗試玩一張紙牌,拿0…許多張紙牌,而playersHand表示玩家在玩手。 驗證是在幕后進行的,以確保任何舉動在提交之前都是合法的。
回送 (Loopback)
Loopback is a rich API framework created by StrongLoop and has no less an entity than IBM backing it. With lots of features you’d expect from any enterprise-grade framework such as the ability to easily protect endpoints that require authentication, all the tools needed to build custom authorisation decorators easily, a CLI tool for scaffolding controllers, services and repositories etc. Loopback allowed me to quickly get productive and setup an API that would allow players to play online!
回送是由StrongLoop創建的豐富API框架,其實體不亞于IBM支持它的實體。 您可以從任何企業級框架中獲得許多功能,例如能夠輕松保護需要身份驗證的端點的功能,輕松構建自定義授權裝飾器所需的所有工具,用于搭建控制器,服務和存儲庫的CLI工具等。讓我快速提高工作效率,并設置一個允許玩家在線玩的API!
The first step is to install the Loopback CLI tool:
第一步是安裝Loopback CLI工具:
npm install -g @loopback/cli
npm install -g @loopback/cli
Then simply run lb4, follow the instructions, and Loopback will scaffold all of the bits needed for a microservice. Once this was done I added some services, which was achieved using lb4 service from the root of the application folder. The structure of the src folder where the code lives is given in Figure 2.
然后只需運行lb4 ,按照說明進行操作,然后環回將支持微服務所需的所有位。 完成此操作后,我添加了一些服務,這些服務是使用應用程序文件夾根目錄中的lb4 service實現的。 代碼所在的src文件夾的結構如圖2所示。
Figure 2: The src folder of a Loopback application with services added圖2:添加了服務的Loopback應用程序的src文件夾The patterns used here are fairly standard for a CRUD API — controllers, talking to services, which talk to repositories which talk to data stores… the first question one might ask is why can’t I just create this by hand and avoid the need to learn the Loopback framework? As mentioned before Loopback gives you a lot out of the box — it has an ORM framework with wrappers around common data commands and queries so you can interact with a database without having to write a line of SQL; so to update the player in the game with the id of id with the player indicated by player we could do:
此處使用的模式對于CRUD API來說是相當標準的-控制器,與服務對話,與存儲庫對話,與數據存儲對話……一個人可能會問的第一個問題是,為什么我不能只手工創建它,而不必學習環回框架? 如前所述,Loopback為您提供了很多開箱即用的功能–它具有一個ORM框架,該框架帶有用于常見數據命令和查詢的包裝器,因此您可以與數據庫進行交互而無需編寫SQL。 因此要使用ID為id的游戲者更新游戲中的游戲player我們可以執行以下操作:
await super.updateAll({player1:player}, {and: [{id}, {playerId: null}],
});
It can also create entities POJOs (or should than be POTSOs?) using the CLI tool… it adds ES-linting, scaffolds tests, sets up NPM scripts and wires up Swagger, has it’s own IoC framework… and a lot more.
它還可以使用CLI工具創建實體POJO(或者應該是POTSO?)……它添加了ES-lint,腳手架測試,設置了NPM腳本并建立了Swagger,具有自己的IoC框架……等等。
OAuth2 (OAuth2)
In order to play an online game you first need to establish some sort of identity. Traditionally this might be achieved by having a database of users that new users can register with, setting a password and verifying their email address using a one-time password (OTP). This is arguably the simplest to develop and test, however more and more service providers from all walks of life are delegating responsibility to well-establish third parties such as Google and Facebook. You’ve probably seen this at some point — you join a site whose services you want to access and they allow you to sign up with one of a select list of providers. There are a number of benefits to this approach — the user journey is simplified, you no longer need to concern yourself with storing potentially sensitive data in a database, users don’t have to manage yet-another-set-of-credentials, and so on.
為了玩在線游戲,您首先需要建立某種身份。 傳統上,這可以通過擁有新用戶可以注冊的用戶數據庫,設置密碼并使用一次性密碼(OTP)驗證其電子郵件地址來實現。 可以說,這是最簡單的開發和測試,但是越來越多的各行各業的服務提供商將責任委托給了建立良好的第三方,例如Google和Facebook。 您可能已經看到了這一點-您加入了一個您想訪問其服務的站點,這些站點使您可以通過選擇的提供者列表之一進行注冊。 這種方法有很多好處-簡化了用戶流程,您不再需要擔心將潛在的敏感數據存儲在數據庫中,用戶不必管理另一組憑據,并且以此類推。
Figure 3: An example of the auth prompt shown to a user attempting to authenticate with OAuth2圖3:向用戶顯示嘗試通過OAuth2進行身份驗證的身份驗證提示示例For this project I set up OAuth2 with both Google and Facebook, which involves a bit of work with those providers such as explicitly defining redirect URIs.
對于這個項目,我同時與Google和Facebook一起設置了OAuth2,這涉及到與這些提供程序的一些工作,例如顯式定義重定向URI。
OAuth2 providers require a callback URL once the client has given their consent, and for a developer this would then entail writing an webhook to handle the callback, authenticating with the provider using a token that was issued to access protected resources (such as the user’s name and email address)... which doesn’t sound like a lot of fun. Luckily For NodeJS developers a library for handling a vast range of common authentication scenarios already exists — passportjs.
一旦客戶同意,OAuth2提供程序就需要一個回調URL,對于開發人員而言,這將需要編寫一個Webhook來處理該回調,并使用發出用于訪問受保護資源(例如用戶名)的令牌向提供程序進行身份驗證。和電子郵件地址)...聽起來并不有趣。 幸運的是,對于NodeJS開發人員來說,已經存在一個用于處理各種常見身份驗證方案的庫– passwordjs 。
Passport strategies (as they are know) do not work out of the box with Loopback (it targets Express), but can be made to work using an adapter pattern that involves wrapping native passport strategies in a Loopback middleware that calls down to native passport authentication; I took inspiration from this example. This middleware is then invoked on callback and the correct strategy used to authenticate. A signed JWT is issued which can be used to take part in games by providing it in the Authentication header as a bearer token. Because it is a JWT no further interaction with the provider is necessary while the token is valid, and it is signed so the claims cannot be tampered with.
護照策略(眾所周知)不能與Loopback配合使用(針對Express),但可以使用適配器模式來工作,該適配器模式包括將本機護照策略包裝在Loopback中間件中,從而調用本機護照身份驗證; 我從這個例子中得到了啟發。 然后在回調上調用此中間件,并使用正確的策略進行身份驗證。 發出簽名的JWT,可以通過將其作為Authentication令牌提供在Authentication標頭中來參與游戲。 由于它是JWT,因此令牌有效時就不需要與提供者進行進一步的交互,并且令牌已簽名,因此不能篡改聲明。
Figure 4: Loopback/Passport adapter圖4:環回/護照適配器采取行動 (Making a move)
The data store is fairly basic — a SQL Server table stores all games in progress and a serialised copy of the state of a game. When a player makes a move, the game is pulled out of the database, deserialised (using the Scopa engine I’d built), the move is played, the game is serialised and saved back into the database. The Engine acts as a state machine and will only allow valid moves (for example a player can only move when it is their turn).
數據存儲是相當基本的-SQL Server表存儲所有進行中的游戲和游戲狀態的序列化副本。 當玩家進行移動時,將游戲從數據庫中拉出,進行反序列化(使用我構建的Scopa引擎),進行移動,將游戲序列化并保存回數據庫中。 引擎充當狀態機,并且僅允許有效移動(例如,玩家只能在回合時移動)。
測試中 (Testing)
The application can be spun up locally and a game can be played given valid JWT tokens. For automated testing I stubbed out the auth providers and used docker compose to create a) the application and b) the database, within a local Docker network where acceptance tests can be run.
可以在本地啟動該應用程序,并且可以使用有效的JWT令牌來玩游戲。 對于自動化測試,我在Docker本地網絡中運行身份驗證提供程序并使用docker compose創建a)應用程序和b)數據庫。
在Azure中托管 (Hosting in Azure)
As a side-project one of my goals is to get hands-on with technologies that are interesting or likely to be valuable in my day-to-day work. As such, I decided to host the application in Azure on AKS (other options are available in Azure, notably Web App for Containers). I would need to setup a Kubernetes cluster in Azure, which costs a few pounds a week to keep running. Luckily my current employer gives me some free Azure credits every month as part of my MSDN subscription, so I was able to use these.
作為附帶項目,我的目標之一是動手使用有趣或可能對我的日常工作有價值的技術。 因此,我決定將應用程序托管在AKS上的Azure中(其他選項在Azure中可用,尤其是容器Web應用程序 )。 我需要在Azure中設置一個Kubernetes集群,每周花費幾英鎊來保持運行。 幸運的是,作為MSDN訂閱的一部分,我現在的老板每月都會給我一些免費的Azure信用,因此我可以使用這些信用。
I decided to use Terraform, a tool for infrastructure-as-code that is gaining popularity in the world of devops. These days creating infrastructure using point-and-click user interfaces is frowned upon in most scenarios for good reasons that are beyond the scope of this article. Scripts can also accomplish these tasks, but lack the state-tracking of Terraform, which is a powerful tool for ensuring changes to code can easily be reflected by the provisioned resources.
我決定使用Terraform,這是一種用于將基礎結構作為代碼的工具,在devop的世界中越來越受歡迎。 如今,在大多數情況下,使用點擊用戶界面創建基礎結構的想法已經超出了本文的討論范圍。 腳本也可以完成這些任務,但是缺少Terraform的狀態跟蹤,Terraform是一種功能強大的工具,可確保已調配的資源可以輕松反映代碼的更改。
To give you an example of it’s succinctness, this is all it takes to spin up a Kubernetes cluster comprising 2 nodes:
舉一個簡潔的例子,這就是啟動一個包含2個節點的Kubernetes集群的全部工作:
resource "azurerm_kubernetes_cluster" "scoparella-kube" {name = "${var.environment}-scoparella-aks1"
location = var.location
resource_group_name = var.resource_group_name
dns_prefix = "${var.environment}scoparellaaks1"
node_resource_group = "${var.environment}-scoparella-aks-rg"
default_node_pool {
name = "agentpool"
node_count = 2
vm_size = "Standard_B2s"
} identity {
type = "SystemAssigned"
} lifecycle {
prevent_destroy = false
} tags = {
environment = var.environment
}
}
Terraform resources can be organised into modules, and I also had modules for resources such as KeyVault which was used to store the database password among other things.
Terraform資源可以組織為模塊,我還具有諸如KeyVault之類的資源模塊,這些模塊曾用于存儲數據庫密碼。
In addition to terraform I also defined the application deployment using the standard Kubernetes YAML format; I did experiment with defining these natively in HashiCorp Configuration Language (HCL — the configuration language of Terraform), but opted to use YAML instead as it was more familiar to me, and better supported and documented. Database objects (DBOs) were applied using sqlcmd .
除了terraform之外,我還使用標準的Kubernetes YAML格式定義了應用程序部署。 我確實嘗試過使用HashiCorp配置語言(HCL-Terraform的配置語言)本地定義它們,但是選擇使用YAML代替,因為它對我來說比較熟悉,并且得到了更好的支持和記錄。 使用sqlcmd應用數據庫對象(DBO)。
I faced several challenges during the process of scripting up the infrastructure. The biggest obstacle was finding a way to access secrets held in KeyVault. Kubernetes has its own approaches to secrets management, however I chose to use a project called AAD Pod Identity which allows Kubernetes applications to access resources in Azure (such as KeyVault) by authenticating with Azure Active Directory and assuming a role with the privileges required. I created roles and identities using terraform, but applied the deployment of the identity pods using Kubernetes YAML and some bash to extract the relevant UUIDs dynamically. On application startup the Scopa API application it will pull the secrets it needs from KeyVault and cache them locally.
在編寫基礎結構腳本的過程中,我遇到了一些挑戰。 最大的障礙是找到一種方法來訪問KeyVault中保存的機密。 Kubernetes具有自己的秘密管理方法,但是我選擇使用一個名為AAD Pod Identity的項目,該項目允許Kubernetes應用程序通過向Azure Active Directory進行身份驗證并承擔具有所需特權的角色來訪問Azure中的資源(例如KeyVault)。 我使用terraform創建了角色和身份,但是使用Kubernetes YAML和一些bash應用了身份吊艙的部署來動態提取相關的UUID。 在應用程序啟動時,Scopa API應用程序將從KeyVault中提取所需的機密并將其本地緩存。
Finally I applied a cloud-network load balancer, binding a public IP address (on port 80) to the internal IP address of the service (on port 3000). With this in place I could verify liveness over the public internet using curl to a /ping endpoint, confirming the cluster was setup correctly.
最后,我使用了一個云網絡負載平衡器,將一個公共IP地址(在端口80上)綁定到該服務的內部IP地址(在端口3000上)。 有了這個適當的位置,我可以使用curl到/ping端點來驗證公共互聯網上的活動,確認集群已正確設置。
apiVersion: v1kind: Service
metadata:
name: "scoparella-api-service"
spec:
type: LoadBalancer
selector:
app: scoparella-app
ports:
- protocol: TCP
port: 80
targetPort: 3000
API管理服務 (API Management Services)
Clearly accessing a backend via it’s public IP address over an insecure connection wasn’t a desirable end-state. I used API Management Services to act as a reverse proxy to the load balancer service (over HTTPS). To do this I needed to add the API Management service to the AKS VNet, allocate an address space for it, and select the subnet from the VNet configuration of the API Management Service (Figure 5). There are challenges doing this at present with Terraform so I was forced to use the Azure UI. Scripting this up is on my todo list, even if just in a bash script.
顯然,通過不安全的連接通過后端的公共IP地址訪問后端不是理想的最終狀態。 我使用API?? Management Services充當負載平衡器服務(通過HTTPS)的反向代理。 為此,我需要將API Management服務添加到AKS VNet,為其分配地址空間,然后從API Management Service的VNet配置中選擇子網(圖5)。 目前,使用Terraform會遇到很多挑戰,因此我被迫使用Azure UI。 即使在bash腳本中,也可以在此腳本上編寫腳本。
Figure 5: Pointy-clicky for setting API Management VNet Subnet圖5:設置API管理VNet子網的鼠標單擊Azure開發人員 (Azure Devops)
Finally for CI/CD I chose to use Azure Devops. This is a tool we are using extensively in my current role, and it has the advantage of being fully managed and it integrates well with the rest of the Azure ecosystem. Pipelines are defined using YAML, and a base image can be selected to fit particular requirements. I chose Ubuntu, and setup an Azure pipeline to checkout the code, run tests inside a container, terraform, and apply deployments using kubectl.
最后,對于CI / CD,我選擇使用Azure Devops。 這是我目前擔任職務時廣泛使用的工具,它具有受到完全管理的優勢,并且與Azure生態系統的其余部分很好地集成在一起。 管道是使用YAML定義的,并且可以選擇基本圖像以滿足特定要求。 我選擇了Ubuntu,并設置了Azure管道來簽出代碼,在容器中運行測試,terraform并使用kubectl應用部署。
These are defined as “tasks” in an Azure Devops pipeline. An example of one is given below:
這些在Azure Devops管道中被定義為“任務”。 下面是一個示例:
- task: Bash@3condition: or( eq('${{ parameters.task }}', '*'), eq('${{ parameters.task }}', 'terraform') )
inputs:
targetType: "inline"
script: |
wget https://releases.hashicorp.com/terraform/0.12.29/terraform_0.12.29_linux_amd64.zip
unzip terraform_0.12.29_linux_amd64.zip
./terraform init
./terraform plan
./terraform apply -auto-approve
workingDirectory: "./resources/${{ parameters.stage }}"
displayName: "Terraform data/secrets"
While this is just some bash, Devops also has templates for common task, for example building and pushing a Docker image:
盡管這只是一些麻煩,但Devops還具有用于常見任務的模板,例如,構建和推送Docker映像:
- task: Docker@2displayName: Build and Push
inputs:
containerRegistry: "dockerscoparella"
repository: "garrypassarella/scoparella"
command: "buildAndPush"
Dockerfile: "Dockerfile"
tags: |
scoparella_api_${{ variables.env }}
condition: or( eq('${{ parameters.task }}', '*'), eq('${{ parameters.task }}', 'docker') )
One caveat is that Azure Devops requires an identity in Azure Active Directory with the privileges necessary to provision resources in Azure; my organisation do not grant me the ability to create these, so I was forced to do an Azure login whenever I wanted to run a build — a bit clunky, but something I wouldn’t face if I owned the subscription. For similar reasons I was unable to use Azure Container Registry (ACR) but I got around this by using Docker Hub and setting up a service connection.
一個警告是,Azure Devops要求在Azure Active Directory中具有一個身份,該身份具有在Azure中置備資源所必需的特權; 我的組織沒有授予我創建這些功能的能力,因此,每當我要運行構建時,我都被迫進行Azure登錄–有點笨拙,但是如果擁有訂閱,我將不會面對。 出于類似的原因,我無法使用Azure容器注冊表(ACR),但是通過使用Docker Hub并設置服務連接來解決此問題。
下一步? (Next steps?)
Unfortunately my Azure credits ran out after 2 weeks (implying I might need to swat up on cost optimisation next, or that Azure is just very expensive). I still have some things I’d like to do to this project, in particular script out the API Management parts. In the meantime I am looking at building a web-based front-end for the game using React. That might be the subject of another article in a few months…
不幸的是,我的Azure信用額度在2周后就用光了(這意味著我接下來可能需要進行成本優化,否則Azure會非常昂貴)。 我仍然想對此項目做一些事情,特別是將API管理部分腳本化。 同時,我正在考慮使用React構建游戲的基于Web的前端。 這可能是幾個月后另一篇文章的主題。
The full code for the API is here: https://github.com/garrypas/scoparella.api
API的完整代碼在這里: https : //github.com/garrypas/scoparella.api
For the Scoparella Engine here: https://github.com/garrypas/scoparella.engine
對于此處的Scoparella引擎: https : //github.com/garrypas/scoparella.engine
翻譯自: https://medium.com/@garry.passarella/building-a-typescript-based-gaming-back-end-with-loopback-aks-and-terraform-b533c9485e80
python aks
總結
以上是生活随笔為你收集整理的python aks_使用环回aks和terraform构建基于打字稿的游戏后端的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 手机gnss定位相关知识
- 下一篇: 【Linux基本知识】