Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better micro-infrastructure with Gradle composite builds #146

Merged
merged 49 commits into from
Feb 27, 2024
Merged
Changes from 1 commit
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
e21244f
Locally building
gchristov Feb 23, 2024
417178e
Locally running
gchristov Feb 24, 2024
70af72e
Locally running tests
gchristov Feb 25, 2024
fcac839
Add kotlinUpgradeYarnLock
gchristov Feb 25, 2024
aba4301
Remove yarn lock files
gchristov Feb 25, 2024
a10399a
Readd
gchristov Feb 25, 2024
7387893
Rename jobs
gchristov Feb 25, 2024
1468f8e
Remove gradle cache
gchristov Feb 25, 2024
d157d00
remove yarn lock files
gchristov Feb 25, 2024
0167258
try single service
gchristov Feb 25, 2024
8207955
Fix ci docker and readd yarn lock files
gchristov Feb 25, 2024
3467beb
Ignore infra for now
gchristov Feb 25, 2024
32ebfb1
remove lockfiles and collect generated ones
gchristov Feb 25, 2024
bcf325a
Try with auto generated lock files
gchristov Feb 25, 2024
5167320
Attempt another
gchristov Feb 25, 2024
f713940
Customise CI file for search service
gchristov Feb 25, 2024
8b492c8
Another CI update
gchristov Feb 25, 2024
e337fcf
Add self-destruct moduke
gchristov Feb 25, 2024
3bc7ef1
Add statistics module
gchristov Feb 25, 2024
de04b1f
Add slack module
gchristov Feb 25, 2024
e50622a
Add landing page module
gchristov Feb 25, 2024
be73d6b
Typo
gchristov Feb 25, 2024
74dac19
Add proxy web module
gchristov Feb 25, 2024
5d2cd5a
Readd root gradle project config
gchristov Feb 25, 2024
e70f8d5
Fix local run
gchristov Feb 25, 2024
aeb3365
Attempt to see if we can install a yaml merge tool via homebrew
gchristov Feb 25, 2024
6b5e46d
Another attempt
gchristov Feb 25, 2024
de438aa
Oups forgot the actual run script
gchristov Feb 25, 2024
d67db9f
Undo change
gchristov Feb 25, 2024
173a910
Re-enable infra preview
gchristov Feb 25, 2024
9687c65
Pulumi micro-stack architecture
gchristov Feb 26, 2024
7220cf4
Add CI check for common
gchristov Feb 26, 2024
1ac50ef
Tidy up common CI
gchristov Feb 27, 2024
23546c1
Second attempt
gchristov Feb 27, 2024
012af73
Tidy up landing page ci
gchristov Feb 27, 2024
0f34f24
Tidy up proxy ci
gchristov Feb 27, 2024
e745d51
Tidy up search ci
gchristov Feb 27, 2024
7d3e481
Tidy up self-destruct ci
gchristov Feb 27, 2024
1de7915
Tidy up slack ci
gchristov Feb 27, 2024
d3668c6
no anchors
gchristov Feb 27, 2024
84411fa
Tidy up statistics ci
gchristov Feb 27, 2024
525bc99
Duplicate secrets in service test jobs
gchristov Feb 27, 2024
a47cff4
Deploy CI pipelines
gchristov Feb 27, 2024
406f53a
Swap checks to test CI deployment
gchristov Feb 27, 2024
334885d
Fix check names
gchristov Feb 27, 2024
2a1effd
Revert "Swap checks to test CI deployment"
gchristov Feb 27, 2024
fe04d65
Tidy up
gchristov Feb 27, 2024
ac8bd37
Remove old Pulumi stack
gchristov Feb 27, 2024
def5bb8
Update readme
gchristov Feb 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Update readme
  • Loading branch information
gchristov committed Feb 27, 2024
commit def5bb8192d4f0f15a62723bc3e34a6bb4ec82ab
63 changes: 34 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
[![Deployment (GCP)](https://github.com/gchristov/thecodinglove-kotlinjs/actions/workflows/deploy.yml/badge.svg)](https://github.com/gchristov/thecodinglove-kotlinjs/actions/workflows/deploy.yml)

# About

`thecodinglove-kotlinjs` is a cutting-edge Kotlin multiplatform project, powering [TheCodingLove GIFs](https://slack.com/apps/AFNEWBNFN) Slack app. Built with [KotlinJS](https://kotlinlang.org/docs/js-overview.html), it seamlessly bridges Kotlin and Javascript to bring a fully serverless platform, currently deployed as a [Docker](https://www.docker.com/) container on [Google Cloud](https://cloud.google.com/run) using [Pulumi](https://www.pulumi.com/) infrastructure as code.
`thecodinglove-kotlinjs` is a cutting-edge Kotlin multiplatform project, powering [TheCodingLove GIFs](https://slack.com/apps/AFNEWBNFN) Slack app. Built with [KotlinJS](https://kotlinlang.org/docs/js-overview.html), it seamlessly bridges Kotlin and Javascript to bring a fully serverless platform, currently deployed as microservice [Docker](https://www.docker.com/) containers on [Google Cloud](https://cloud.google.com/run) using [Pulumi](https://www.pulumi.com/) infrastructure as code.

<details>
<summary>🛠 Tech stack</summary>

- [Hexagon architecture](https://en.m.wikipedia.org/wiki/Hexagonal_architecture_(software)) - implemented as domain, adapter and service sub-projects for each microservice
- [Hexagon microservice architecture](https://en.m.wikipedia.org/wiki/Hexagonal_architecture_(software)) - implemented as `domain`, `adapter` and `service` sub-projects for each microservice
- [KotlinJS](https://kotlinlang.org/docs/js-overview.html) - NodeJS transpiling
- [PubSub](https://cloud.google.com/pubsub) - event-driven messaging
- [Firestore](https://firebase.google.com/docs/firestore) - NoSQL database
- [Docker](https://www.docker.com/) - containerised deployment
- [Cloud Run](https://cloud.google.com/run) - serverless deployment of containers
- [Cloud Run](https://cloud.google.com/run) - serverless deployment of microservices
- [Cloud Scheduler](https://cloud.google.com/scheduler) - cron jobs
- [GitHub Actions](https://github.com/features/actions) - CI automation
- [Pulumi](https://www.pulumi.com/) - infrastructure as code
- [nginx](https://nginx.org/) - API reverse proxy
- [Pulumi](https://www.pulumi.com/) - infrastructure as code, using [micro-stacks](https://www.pulumi.com/docs/using-pulumi/organizing-projects-stacks/#micro-stacks)
- [nginx](https://nginx.org/) - web reverse proxy
</details>

🌍 [Live demo](https://thecodinglove.crowdstandout.com)

## Setup

The project can be run locally and on the cloud - in this case Google Cloud via Pulumi. The local build is generally independent but it still talks to a Firestore database and sends PubSub messages, so the cloud setup is still required.
The project can be run locally and deployed on the cloud - in our case to Google Cloud via Pulumi. The local build talks to a Firestore database and sends PubSub messages, so the cloud setup is a prerequisite.

The below setup assumes you've already cloned the project locally.

<details>
<summary>1️⃣ Google Cloud setup</summary>
Expand All @@ -38,20 +38,25 @@ The project can be run locally and on the cloud - in this case Google Cloud via
- `Cloud Scheduler Admin`
- (Optional) If you're specifying a custom domain mapping, as we are, [verify domain ownership and add your service account as owner](https://search.google.com/search-console).
3. Export a JSON API key for your Service Account and call it `credentials-gcp-infra.json`.
4. [Signup and Install Pulumi](https://www.pulumi.com/docs/clouds/gcp/get-started/begin/#install-pulumi).
5. Create a Pulumi access token and login locally using `pulumi login`.
6. Create a new empty folder under the root of the project, called `infra` and `cd` into it.
7. Create an empty Pulumi project with no resources using the `pulumi new` command and follow the instructions:
- you can use the prompt `Empty project with no resources` for Pulumi AI
- you can use `prod` as your stack name
8. Replace the created `Pulumi.yaml` file with the one from the existing `pulumi` folder, preserving the original `name` and paste the Service Account JSON API key file there too.
9. Setup Pulumi with your Google Cloud project ID and credentials:
- `pulumi config set gcp:credentials credentials-gcp-infra.json`
- `pulumi config set gcp:project GCP_PROJECT_ID`
10. Run `pulumi up` to automatically create the required project infrastructure.
11. Find your new `firebase-adminsdk` Service Account and give it the following additional roles:
- `Pub/Sub Publisher`, for publishing messages to PubSub topics
12. Export a JSON API key for your `firebase-adminsdk` Service Account and call it `credentials-gcp-app.json` - the app will need it later.
4. [Signup and Install Pulumi](https://www.pulumi.com/docs/clouds/gcp/get-started/begin/#install-pulumi) locally.
5. Create a Pulumi [access token](https://www.pulumi.com/docs/pulumi-cloud/access-management/access-tokens/) and login locally using `pulumi login`.
6. The project uses Pulumi micro-stacks to deploy the microservices individually. Each microservice has a corresponding `infra` folder containing its `Pulumi.yaml` infrastructure program, eg `search/infra`. To get the project going, you will need to manually initialise each microservice on GCP using the Pulumi scripts.
```
The order to do this matters, so go with common/infra first, then all other microservices, then proxy-web/infra. The reason is that the resouces are created incrementally at each stage and we currently have no way synchronize them.
```
7. The steps to deploy a microservice's infrastructure is the same for all:
1. Navigate to its `infra` folder.
2. Paste the `credentials-gcp-infra.json` file.
3. Create a new empty Pulumi project with no resources using the `pulumi new` command and follow the instructions:
- you can use the prompt `Empty project with no resources` for Pulumi AI;
- you can use `prod` as your stack name;
4. Replace the `name` in the microservice `Pulumi.yaml` with the value you entered in the prompt.
5. Open `Pulumi.prod.yml` and replace the `gcp:project` value with your project id.
6. Run `pulumi up` to automatically create the required microservice infrastructure.
7. Repeat for the remaining microservices.
8. Find your auto-generated `firebase-adminsdk` Service Account and give it the following additional roles:
- `Pub/Sub Publisher`, for publishing messages to PubSub topics;
9. Export a JSON API key for your `firebase-adminsdk` Service Account and call it `credentials-gcp-app.json` - the app will need it later.
</details>

<details>
Expand All @@ -61,21 +66,21 @@ The project powers an [existing Slack app](https://slack.com/apps/AFNEWBNFN), so

1. Create a new Slack app.
2. You will need an SSH tunnel to your localhost for Slack's APIs. You can use [serveo.net](https://serveo.net) for free and configure it with this command `ssh -R YOUR_DOMAIN.serveo.net:80:localhost:3000 serveo.net`.
3. Point the following Slack features to the relevant project APIs that know how to respond to them using the url you used for [serveo.net](https://serveo.net):
3. Point the following Slack features to the relevant project API endpoints that know how to respond to them using the url you used for [serveo.net](https://serveo.net):
- [Slash commands](https://api.slack.com/slash-commands) -> `YOUR_DOMAIN.serveo.net/api/slack/slash`
- [OAuth](https://api.slack.com/authentication/oauth-v2) -> `YOUR_DOMAIN.serveo.net/api/slack/auth`
- [Events](https://api.slack.com/events-api) -> `YOUR_DOMAIN.serveo.net/api/slack/event`
- [Interactivity](https://api.slack.com/messaging/interactivity) -> `YOUR_DOMAIN.serveo.net/api/slack/interactivity`
4. Note down your `Slack Client ID`, `Secret` and `Signing Secret`.
4. Make a note of your `Slack Client ID`, `Secret` and `Signing Secret`.
</details>

<details>
<summary>3️⃣ Local setup</summary>

1. [Install Docker Desktop](https://docs.docker.com/get-started/) and start it up. No additional configuration is required as the project uses Docker Compose to run locally. Checkout the `docker` folder for the setup.
2. [Install IntelliJ](https://www.jetbrains.com/help/idea/installation-guide.html). This project has been tested with `IntelliJ IDEA 2023.2.5`.
3. Clone the repository and open the project with IntelliJ.
4. Create a Slack channel to receive server error messages and monitoring updates. The project is configured to post all unhandled `Throwable`s to that channel. We use the [Incoming Webhooks](https://slack.com/apps/A0F7XDUAZ-incoming-webhooks) app.
3. Open the root project with IntelliJ and wait for it to initialise.
4. Create a Slack channel to receive server error messages and monitoring updates. The project is configured to post all unhandled `Throwable`s to that channel. We use the [Incoming Webhooks](https://slack.com/apps/A0F7XDUAZ-incoming-webhooks) app to obtain a channel URL webhook.
5. Create the following `secrets.properties` files:
```
# Under /slack/adapter/secrets.properties
Expand All @@ -101,7 +106,7 @@ This is really up to you! However, we've provided our setup below.
<details>
<summary>GitHub Actions</summary>

The project is configured to build with [GitHub Actions](https://github.com/features/actions). Checkout the `.github` folder for the workflows. Follow these steps to configure the CI environment:
The project is configured to build with [GitHub Actions](https://github.com/features/actions) and have a separate workflow for each microservice. Checkout the `.github` folder for details. Follow these steps to configure the CI environment:

1. Add your Pulumi access token as a [GitHub encrypted secret](https://docs.github.com/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets) with the name `PULUMI_ACCESS_TOKEN`.
2. Each of the variables defined in the `secrets.properties` files you created above should be exposed as GitHub encrypted secrets, using the same names as keys.
Expand All @@ -110,6 +115,6 @@ The project is configured to build with [GitHub Actions](https://github.com/feat
5. (Optional) Install the [Pulumi GitHub app](https://www.pulumi.com/docs/using-pulumi/continuous-delivery/github-app/) to get automated summaries of your infrastructure as code changes directly on your PR.

Once this is done:
- opening pull requests against the repo will trigger build/test checks as well as infrastructure changes preview
- merging pull requests to the main branch deploys the app and any infrastructure changes to Google Cloud
- opening pull requests against the repo will trigger build/test checks as well as infrastructure changes preview for the microservice that has been changed;
- merging pull requests to the main branch deploys the changes to the corresponding microservice to Google Cloud;
</details>
Loading