Skip to content

Commit

Permalink
fix: improving k8s usecase support (#18)
Browse files Browse the repository at this point in the history
* fix: improving k8s usecase support

* chore: added logic for capturing env

* chore: working logic

* chore: fixed permission issue

* chore: updated README

* docs: added image

* chore: fixed service script to handle no hostname

* chore: updated Caddyfile

* chore: updated script to handle namespaces

* Apply suggestions from code review

Co-authored-by: Adelina Simion <[email protected]>

* docs: updated the README

---------

Co-authored-by: Adelina Simion <[email protected]>
  • Loading branch information
karl-cardenas-coding and addetz authored Mar 27, 2024
1 parent 896386a commit 3570a1a
Show file tree
Hide file tree
Showing 11 changed files with 435 additions and 23 deletions.
3 changes: 2 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ node_modules/
static/
build/
*log
.env
.env
deployment/
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,8 @@ build/

*.DS_Store

*log
*log

# Deployment Internal

internal-k8s.yaml
5 changes: 3 additions & 2 deletions Caddyfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@
}
}
:3000 {
reverse_proxy /api/* {
header_up Authorization "Bearer {$TOKEN}"
reverse_proxy /api/* {
# Uncomment the following line to always inject the Authorization header with the token
# header_up Authorization "Bearer {$TOKEN}"
to {$SVC_URI}
}
log {
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
FROM node:18-alpine AS modules
WORKDIR /app
COPY . .
RUN npm ci && npm run build && \
adduser -u 1002 -D appuser appuser
RUN adduser -u 1002 -h /home/appuser -D appuser appuser && \
npm ci && npm run build


FROM node:18-alpine AS production
Expand Down
28 changes: 16 additions & 12 deletions Dockerfile.Caddy
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
FROM node:18-alpine AS modules
WORKDIR /app
COPY . .
RUN npm ci && npm run build && \
adduser -u 1002 -D appuser appuser
RUN adduser -u 1002 -h /home/appuser -D appuser appuser && \
npm ci && npm run build

FROM caddy:2.6.4-alpine as caddy

FROM caddy:2.7.6-alpine as caddy

FROM node:18-alpine AS production
LABEL org.opencontainers.image.source="https://github.com/spectrocloud/hello-universe"
Expand All @@ -14,25 +15,28 @@ WORKDIR /app
ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1
ENV PORT 8080
ENV API_PORT 3000
ENV API_URI ""
ENV SVC_URI ""
ENV API_VERSION 1
ENV TOKEN ""
ENV QUERY_K8S_API ""

COPY --from=modules /etc/passwd /etc/passwd
COPY --from=modules /etc/group /etc/group
COPY --from=modules --chown=appuser:appuser /home/appuser/ /home/appuser/
COPY --from=modules --chown=appuser:appuser /app/node_modules ./node_modules
COPY --from=modules --chown=appuser:appuser /app/build ./build
COPY --from=modules --chown=appuser:appuser /app/package.json ./package.json
COPY --from=caddy --chown=appuser:appuser /usr/bin/caddy /usr/bin/caddy
COPY --from=modules --chown=appuser:appuser /app/Caddyfile /etc/caddy/Caddyfile
COPY --from=modules --chown=1002:1002 /home/appuser/ /home/appuser/
COPY --from=modules --chown=1002:1002 /app/node_modules ./node_modules
COPY --from=modules --chown=1002:1002 /app/build ./build
COPY --from=modules --chown=1002:1002 /app/package.json ./package.json
COPY --from=caddy --chown=1002:1002 /usr/bin/caddy /usr/bin/caddy
COPY --from=modules --chown=1002:1002 /app/Caddyfile /etc/caddy/Caddyfile
COPY --from=modules --chown=1002:1002 /app/scripts/service-ip.sh /app/service-ip.sh

RUN apk update && apk upgrade && apk add --no-cache curl ca-certificates bash jq && \
mkdir -p /var/log/caddy/ && chown -R appuser:appuser /var/log/caddy/ && \
chmod -R 700 /var/log/caddy/
mkdir -p /var/log/caddy/ && chown -R 1002:1002 /var/log/caddy/ && \
chmod -R 700 /var/log/caddy/ && touch /app/.env && chown 1002:1002 /app/.env

USER appuser
EXPOSE 8080 3000
CMD ["/bin/bash", "-c", "REACT_APP_API_URI=$API_URI REACT_APP_API_VERSION=$API_VERSION npx react-inject-env set && \
CMD ["/bin/bash", "-c", "/app/service-ip.sh && source /app/.env && REACT_APP_API_URI=$API_URI REACT_APP_API_VERSION=$API_VERSION REACT_APP_TOKEN=$TOKEN npx react-inject-env set && \
caddy run --config /etc/caddy/Caddyfile --adapter caddyfile"]
82 changes: 82 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,88 @@ hello universe application into a Kubernetes cluster or similar architectures an
docker run -p 8080:8080 -p 3000:3000 -e SVC_URI="http://myprivate.api.address.example:3000" -e API_URI="http://myloadbalancer.example:3000" ghcr.io/spectrocloud/hello-universe:1.1.0-proxy
```

#### Reverse Proxy Environment Variables

| Variable | Description | Default |
| --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `SVC_URI` | The URI to the service API, such as the internal Kubernetes container hostname of the API service. | `""` |
| `API_URI` | The fully qualified hostname and port of the API server. In a reverse proxy setting, set this to the service loadbalancer. If `QUERY_K8S_API` set to `true`, leve this parameter empty. | `""` |
| `TOKEN` | The API authorization token. This is only used if the API is configured for authorization. | `""` |
| `QUERY_K8S_API` | Set to `true` to query the Kubernetes API for the service hostname. This is useful when the service is deployed in a Kubernetes cluster. | `false` |

#### Reverse Proxy with Kubernetes

To deploy the Hello Universe application into a Kubernetes cluster, use the deployment manifest in `deployments/k8s.yaml`. Ensure you provide values and update all placeholders in the manifest with the value `<REPLACE_ME>`. The values must be in base64 format.

In a Kubernetes environment, you can use two methods to deploy the Hello Universe application:

1. Use a single load balancer for the UI and API services.
2. Use separate load balancers for the UI and API services.

##### Single Load Balancer

When deploying the Hello Universe application into a Kubernetes cluster, set the `QUERY_K8S_API` environment variable to `true` and set the `API_URI` environment variable to an empty string. This will result in the reverse proxy forwarding API requests to API service. Only a single load balancer is used in this deployment pattern. If authorization is enabled, provide the `auth-token` Kubernetes secret with the API authorization token value. Otherwise, API will fail to authorize requests.

> [!NOTE]
> The `QUERY_K8S_API` environment variable is only used when deploying the Hello Universe application into a Kubernetes cluster. Enabling this environment variable will query the Kubernetes API for the service hostname. You can review the script in the `scripts/service-ip.sh`.
![K8s diagram](./static/img/k8s-diagram.png)

Inside the Hello Universe container, [Caddy](https://caddyserver.com/) is used as a reverse proxy to route requests to the API server. The API server is expected to be listening on port `3000`.

If the Hello Universe API is enabled for authorization, provide the `TOKEN` environment variable with the API authorization token. The default anonymous token is `"931A3B02-8DCC-543F-A1B2-69423D1A0B94"`. The reverse proxy will include the token when forwarding requests to the API server.

> ![TIP]
> If you want to automatically inject the authorization token into the reverse proxy for all API requests, uncomment line 29 in the Caddyfile under **/etc/caddy/**.
> `header_up Authorization "Bearer {$TOKEN}"`
> Issue the command `caddy reload --config /etc/caddy/Caddyfile` to apply the changes.
##### Separate Load Balancers

> ![WARNING]
>
> This deployment pattern will not work in single deployment. You need to deploy the API and UI services separately due to the dependency on the API service. Use the signle deployment pattern if you want to deploy the services together.
To use separate load balancers for the UI and API services, you need to make the following changes to the Kubernetes deployment manifest. Change the API service type to `LoadBalancer`. The API service will have its own load balancer, and you will need to set the UI's `API_URI` environment variable to the fully qualified hostname and port of the API service.

```yaml
apiVersion: v1
kind: Service
metadata:
name: api
namespace: hello-universe
spec:
selector:
app: api
ports:
- protocol: TCP
port: 3000
targetPort: 3000
type: LoadBalancer
```
For the UI service, change the image to the default Hello Universe image.
```yaml
containers:
- name: ui
image: ghcr.io/spectrocloud/hello-universe:1.1.2
imagePullPolicy: Always
ports:
- containerPort: 8080
name: ui
```
The UI service will have its own load balancer, and you will need to set the `API_URI` environment variable to the fully qualified hostname and port of the API service. Leave the `QUERY_K8S_API` environment variable set to `false`, and set `SVC_URI` to an empty string.

```shell
API_URI=http://<EXTERNAL_IP>:3000
SVC_URI=""
QUERY_K8S_API=false
```

If authorization is enabled, provide the `auth-token` Kubernetes secret with the API authorization token value. Otherwise, API will fail to authorize requests.

## Image Verification

We sign our images through [Cosign](https://docs.sigstore.dev/signing/quickstart/). Review the [Image Verification](./docs/image-verification.md) page to learn more.
Expand Down
Loading

0 comments on commit 3570a1a

Please sign in to comment.