leandrodevai commited on
Commit
6592f0b
·
verified ·
1 Parent(s): 51d742f

Sync from GitHub via hub-sync

Browse files
Files changed (2) hide show
  1. README.md +49 -0
  2. infra/bicep/main.bicep +177 -0
README.md CHANGED
@@ -205,6 +205,55 @@ FACEVERIFICATION_DEMO_PASSWORD
205
  FACEVERIFICATION_JWT_SECRET_KEY
206
  ```
207
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
  Example enrollment request:
209
 
210
  ```bash
 
205
  FACEVERIFICATION_JWT_SECRET_KEY
206
  ```
207
 
208
+ ### Azure Container Apps
209
+
210
+ The FastAPI image can also be deployed as an ephemeral Azure Container App from
211
+ the GHCR image published by the container workflow.
212
+
213
+ The deployment is defined in `infra/bicep/main.bicep` and is wired to
214
+ `.github/workflows/deploy-azure-container-app.yml`. The workflow:
215
+
216
+ - creates or reuses the Azure resource group configured in GitHub repository
217
+ variables;
218
+ - deploys a Log Analytics workspace, Container Apps environment, and FastAPI
219
+ Container App;
220
+ - runs the published `ghcr.io/leandrodevai/faceverification:fastapi` image;
221
+ - keeps the app ephemeral with no mounted volume or external vector database;
222
+ - configures `minReplicas: 0` and `maxReplicas: 1`;
223
+ - smoke tests `GET /health` after deployment.
224
+
225
+ Required GitHub repository variables:
226
+
227
+ ```text
228
+ AZURE_CLIENT_ID
229
+ AZURE_LOCATION
230
+ AZURE_RESOURCE_GROUP
231
+ AZURE_TENANT_ID
232
+ AZURE_SUBSCRIPTION_ID
233
+ ```
234
+
235
+ Required GitHub repository secrets:
236
+
237
+ ```text
238
+ FACEVERIFICATION_DEMO_USERNAME
239
+ FACEVERIFICATION_DEMO_PASSWORD
240
+ FACEVERIFICATION_JWT_SECRET_KEY
241
+ ```
242
+
243
+ Optional GitHub repository secrets for private GHCR packages:
244
+
245
+ ```text
246
+ GHCR_PULL_USERNAME
247
+ GHCR_PULL_TOKEN
248
+ ```
249
+
250
+ If the GHCR package is public, those optional secrets can be omitted. If it is
251
+ private, `GHCR_PULL_TOKEN` must be a GitHub token with package read access.
252
+
253
+ To avoid ongoing cost while keeping the OIDC and RBAC setup intact, remove the
254
+ demo resources inside the configured resource group from Azure when they are no
255
+ longer needed.
256
+
257
  Example enrollment request:
258
 
259
  ```bash
infra/bicep/main.bicep ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ targetScope = 'resourceGroup'
2
+
3
+ @description('Azure region for the Container Apps resources.')
4
+ param location string = resourceGroup().location
5
+
6
+ @description('Name of the Azure Container App.')
7
+ param containerAppName string = 'faceverification-api'
8
+
9
+ @description('Name of the Container Apps managed environment.')
10
+ param containerAppsEnvironmentName string = 'cae-faceverification-dev'
11
+
12
+ @description('Name of the Log Analytics workspace used by Container Apps.')
13
+ param logAnalyticsWorkspaceName string = 'law-faceverification-dev'
14
+
15
+ @description('Tags applied to all resources created by this deployment.')
16
+ param tags object = {
17
+ app: 'faceverification'
18
+ environment: 'dev'
19
+ managedBy: 'bicep'
20
+ }
21
+
22
+ @description('Container image to deploy.')
23
+ param image string
24
+
25
+ @description('FastAPI container port.')
26
+ param targetPort int = 8000
27
+
28
+ @description('CPU cores allocated to the app container.')
29
+ param cpu string = '2.0'
30
+
31
+ @description('Memory allocated to the app container.')
32
+ param memory string = '4Gi'
33
+
34
+ @description('Demo username for the protected API endpoints.')
35
+ @secure()
36
+ param demoUsername string
37
+
38
+ @description('Demo password for the protected API endpoints.')
39
+ @secure()
40
+ param demoPassword string
41
+
42
+ @description('JWT signing secret for the FastAPI demo auth.')
43
+ @secure()
44
+ param jwtSecretKey string
45
+
46
+ @description('Optional GHCR username for private package pulls.')
47
+ param registryUsername string = ''
48
+
49
+ @description('Optional GHCR token for private package pulls. Leave empty for public packages.')
50
+ @secure()
51
+ param registryPassword string = ''
52
+
53
+ var registryServer = 'ghcr.io'
54
+ var appSecrets = concat([
55
+ {
56
+ name: 'demo-username'
57
+ value: demoUsername
58
+ }
59
+ {
60
+ name: 'demo-password'
61
+ value: demoPassword
62
+ }
63
+ {
64
+ name: 'jwt-secret-key'
65
+ value: jwtSecretKey
66
+ }
67
+ ], empty(registryPassword) ? [] : [
68
+ {
69
+ name: 'ghcr-password'
70
+ value: registryPassword
71
+ }
72
+ ])
73
+
74
+ var registries = empty(registryPassword) ? [] : [
75
+ {
76
+ server: registryServer
77
+ username: registryUsername
78
+ passwordSecretRef: 'ghcr-password'
79
+ }
80
+ ]
81
+
82
+ resource logs 'Microsoft.OperationalInsights/workspaces@2023-09-01' = {
83
+ name: logAnalyticsWorkspaceName
84
+ location: location
85
+ tags: tags
86
+ properties: {
87
+ sku: {
88
+ name: 'PerGB2018'
89
+ }
90
+ retentionInDays: 30
91
+ }
92
+ }
93
+
94
+ resource environment 'Microsoft.App/managedEnvironments@2024-03-01' = {
95
+ name: containerAppsEnvironmentName
96
+ location: location
97
+ tags: tags
98
+ properties: {
99
+ appLogsConfiguration: {
100
+ destination: 'log-analytics'
101
+ logAnalyticsConfiguration: {
102
+ customerId: logs.properties.customerId
103
+ sharedKey: logs.listKeys().primarySharedKey
104
+ }
105
+ }
106
+ }
107
+ }
108
+
109
+ resource app 'Microsoft.App/containerApps@2024-03-01' = {
110
+ name: containerAppName
111
+ location: location
112
+ tags: tags
113
+ properties: {
114
+ managedEnvironmentId: environment.id
115
+ configuration: {
116
+ activeRevisionsMode: 'Single'
117
+ ingress: {
118
+ external: true
119
+ targetPort: targetPort
120
+ transport: 'auto'
121
+ allowInsecure: false
122
+ }
123
+ secrets: appSecrets
124
+ registries: registries
125
+ }
126
+ template: {
127
+ containers: [
128
+ {
129
+ name: 'api'
130
+ image: image
131
+ env: [
132
+ {
133
+ name: 'APP_VARIANT'
134
+ value: 'fastapi'
135
+ }
136
+ {
137
+ name: 'FACEVERIFICATION_DEVICE'
138
+ value: 'cpu'
139
+ }
140
+ {
141
+ name: 'FACEVERIFICATION_DEMO_USERNAME'
142
+ secretRef: 'demo-username'
143
+ }
144
+ {
145
+ name: 'FACEVERIFICATION_DEMO_PASSWORD'
146
+ secretRef: 'demo-password'
147
+ }
148
+ {
149
+ name: 'FACEVERIFICATION_JWT_SECRET_KEY'
150
+ secretRef: 'jwt-secret-key'
151
+ }
152
+ ]
153
+ resources: {
154
+ cpu: json(cpu)
155
+ memory: memory
156
+ }
157
+ }
158
+ ]
159
+ scale: {
160
+ minReplicas: 0
161
+ maxReplicas: 1
162
+ rules: [
163
+ {
164
+ name: 'http-scale'
165
+ http: {
166
+ metadata: {
167
+ concurrentRequests: '10'
168
+ }
169
+ }
170
+ }
171
+ ]
172
+ }
173
+ }
174
+ }
175
+ }
176
+
177
+ output appUrl string = 'https://${app.properties.configuration.ingress.fqdn}'