Skip to content

Commit 05bfb5d

Browse files
committed
Improve self-hosted Docker onboarding
1 parent c47f700 commit 05bfb5d

7 files changed

Lines changed: 128 additions & 21 deletions

File tree

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,28 @@
22

33
A version of the PolicyEngine API that runs the `calculate` endpoint over household object. To debug locally, run `make debug`.
44

5+
## Quick self-hosted run
6+
7+
If you want to try the API without requesting hosted credentials, run the published Docker image:
8+
9+
```
10+
docker run --rm -p 8080:8080 ghcr.io/policyengine/policyengine-household-api:latest
11+
```
12+
13+
Then inspect the service metadata:
14+
15+
```
16+
curl http://localhost:8080/
17+
```
18+
19+
and send calculations to:
20+
21+
```
22+
http://localhost:8080/us/calculate
23+
```
24+
25+
Hosted API docs live at https://www.policyengine.org/us/api.
26+
527
## Local development with Docker Compose
628

729
To run this app locally via Docker Compose:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Return JSON service metadata from the home endpoint and improve self-hosted Docker guidance, including a container healthcheck and non-root runtime user.

config/README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,15 @@ CONFIG_FILE=config/local.yaml make debug
7777
# Mount a custom config file
7878
docker run -v /path/to/your/config.yaml:/custom/config.yaml \
7979
-e CONFIG_FILE=/custom/config.yaml \
80-
policyengine/household-api
80+
ghcr.io/policyengine/policyengine-household-api:latest
8181
```
8282

8383
#### Docker Compose
8484
```yaml
8585
version: '3.13'
8686
services:
8787
household-api:
88-
image: policyengine/household-api
88+
image: ghcr.io/policyengine/policyengine-household-api:latest
8989
volumes:
9090
- ./my-config.yaml:/app/config/custom.yaml
9191
environment:
@@ -123,7 +123,7 @@ spec:
123123
spec:
124124
containers:
125125
- name: api
126-
image: policyengine/household-api
126+
image: ghcr.io/policyengine/policyengine-household-api:latest
127127
env:
128128
- name: CONFIG_FILE
129129
value: /config/config.yaml
@@ -301,11 +301,12 @@ Use environment variables to override specific settings:
301301

302302
```bash
303303
docker run -e FLASK_DEBUG=1 \
304+
-p 8080:8080 \
304305
-e AUTH__ENABLED=false \ # Disable Auth0 for local dev
305306
-e ANALYTICS__ENABLED=false \ # Disable analytics for local dev
306307
-e AI__ENABLED=false \
307308
-e DATABASE__PROVIDER=sqlite \
308-
policyengine/household-api
309+
ghcr.io/policyengine/policyengine-household-api:latest
309310
```
310311

311312
#### Template Variable Substitution
@@ -359,15 +360,15 @@ docker run -v /path/to/config.yaml:/app/config/custom.yaml \
359360
-v /path/to/values.env:/app/config/values.env \
360361
-e CONFIG_FILE=/app/config/custom.yaml \
361362
-e CONFIG_VALUE_SETTINGS=/app/config/values.env \
362-
policyengine/household-api
363+
ghcr.io/policyengine/policyengine-household-api:latest
363364
```
364365

365366
Or with Docker Compose:
366367
```yaml
367368
version: '3.13'
368369
services:
369370
household-api:
370-
image: policyengine/household-api
371+
image: ghcr.io/policyengine/policyengine-household-api:latest
371372
volumes:
372373
- ./my-config.yaml:/app/config/custom.yaml
373374
- ./my-values.env:/app/config/values.env

gcp/policyengine_household_api/Dockerfile.production

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,19 @@ COPY ./config/default.yaml /app/config/default.yaml
3434
# Copy startup script
3535
COPY ./gcp/policyengine_household_api/start.sh /app/start.sh
3636
RUN chmod +x /app/start.sh
37-
37+
38+
# Drop root privileges in the runtime image.
39+
RUN groupadd policyapi && \
40+
useradd --gid policyapi --create-home policyapi && \
41+
chown -R policyapi:policyapi /app /opt/venv
42+
3843
# Configure environment (runs as root by default)
3944
ENV PATH="/opt/venv/bin:$PATH"
4045
EXPOSE 8080
41-
42-
CMD ["/app/start.sh"]
46+
47+
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
48+
CMD curl --fail --silent http://127.0.0.1:8080/liveness_check || exit 1
49+
50+
USER policyapi
51+
52+
CMD ["/app/start.sh"]
Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,28 @@
1-
def get_home() -> str:
2-
"""Get the home page of the PolicyEngine household API.
1+
import json
32

4-
Returns:
5-
str: The home page.
6-
"""
7-
return f"<h1>PolicyEngine household API</h1><p>Use this API to compute the impact of public policy upon households.</p>"
3+
from flask import Response
4+
5+
6+
def get_home() -> Response:
7+
"""Return service metadata for self-serve and hosted API users."""
8+
9+
response_body = {
10+
"status": "ok",
11+
"message": "PolicyEngine household API",
12+
"result": {
13+
"docs_url": "https://www.policyengine.org/us/api",
14+
"container_image": "ghcr.io/policyengine/policyengine-household-api",
15+
"hosted_calculate_url": "https://household.api.policyengine.org/us/calculate",
16+
"local_calculate_url": "http://localhost:8080/us/calculate",
17+
"health_checks": {
18+
"liveness": "/liveness_check",
19+
"readiness": "/readiness_check",
20+
},
21+
},
22+
}
23+
24+
return Response(
25+
json.dumps(response_body),
26+
status=200,
27+
mimetype="application/json",
28+
)

policyengine_household_api/openapi_spec.yaml

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,39 @@ servers:
1313
paths:
1414
/:
1515
get:
16-
summary: Get the home page of the PolicyEngine API
16+
summary: Get service metadata for the PolicyEngine household API
1717
operationId: get_home
18-
description: Returns the home page of the PolicyEngine API as an HTML string.
18+
description: Returns service metadata, documentation links, and self-hosting hints.
1919
responses:
2020
200:
21-
description: The home page.
21+
description: Service metadata.
2222
content:
23-
text/html:
23+
application/json:
2424
schema:
25-
type: string
25+
type: object
26+
properties:
27+
status:
28+
type: string
29+
message:
30+
type: string
31+
result:
32+
type: object
33+
properties:
34+
docs_url:
35+
type: string
36+
container_image:
37+
type: string
38+
hosted_calculate_url:
39+
type: string
40+
local_calculate_url:
41+
type: string
42+
health_checks:
43+
type: object
44+
properties:
45+
liveness:
46+
type: string
47+
readiness:
48+
type: string
2649
/{country_id}/metadata:
2750
get:
2851
summary: Get metadata for a country
@@ -841,4 +864,4 @@ paths:
841864
paths:
842865
type: object
843866
servers:
844-
type: array
867+
type: array

tests/unit/endpoints/test_home.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import json
2+
3+
4+
class TestHomeEndpoint:
5+
def test_returns_json_service_metadata(self, client):
6+
response = client.get("/")
7+
8+
assert response.status_code == 200
9+
assert response.mimetype == "application/json"
10+
11+
payload = json.loads(response.data)
12+
13+
assert payload["status"] == "ok"
14+
assert payload["message"] == "PolicyEngine household API"
15+
16+
result = payload["result"]
17+
assert result["docs_url"] == "https://www.policyengine.org/us/api"
18+
assert (
19+
result["container_image"]
20+
== "ghcr.io/policyengine/policyengine-household-api"
21+
)
22+
assert result["hosted_calculate_url"] == (
23+
"https://household.api.policyengine.org/us/calculate"
24+
)
25+
assert result["local_calculate_url"] == "http://localhost:8080/us/calculate"
26+
assert result["health_checks"] == {
27+
"liveness": "/liveness_check",
28+
"readiness": "/readiness_check",
29+
}

0 commit comments

Comments
 (0)