We chosen to put the project in GCP because they handle security, backup, auto scaling and many things that are expensive to do by ourselves.
We need several things in order to make the project work and maintainable:
-
a VPC network, in order to build a private network for our application, without any public IP
-
a Cloud SQL, that will store data of the application
-
a Bastion, in order to connect to the Cloud SQL from home (to access or migrate it)
-
an App Engine, which will expose the app outside
-
Cloud Function to receive webhook from twilio (sms status/response)
-
Cloud Tasks queues to do flow control between twilio webhook and the app engine
Do not mess up with any of the fields, especially the "locations" (europe-west1 here) as Google do not allow to update an app engine instance once it has been created. Yeah, you can have many Compute Engine instances, many Cloud SQL instances, but only one f*cking App Engine instance that is not modifiable.
You will find some help in the CONTRIBUTING and in the development setup.
-
Select the new project in the "Select a project" menu
-
Click on the Menu, and then "VCP Network" in the Networking part.
-
Go to https://console.cloud.google.com/marketplace/details/google/vpcaccess.googleapis.com?project=covid-fight-redcall&folder=&organizationId= and enable the Serverless VPC Access API
-
Fill up the form, keep the VPC connector name, it will be used in configuration
-
Click on the menu, then "Compute Engine" in Compute category, then "VM instances".
-
Set-up the compute engine as follow, taking care of the red parts, and click on "Management, Security, Disks...".
-
On Management tab, make sure "On host maintenance" is set to "Migrate VM Instance"
-
On Network tab, select the VPC created earlier and click "Done"
-
Enter your db information and press Create. Care about the "Region".
-
Choose "Private IP" (accept when you will be prompted to enable Network API) and select your network, press Save.
-
Create your new user. Keep those credentials safe, you'll need them soon.
-
Look up for your private IP address and set it in your dotenv (
deploy/<your project>/dotenv
), in the " DATABASE_HOST" variable.
In order to write logs, our application requires a google service account.
-
Enter your service account details (they don't really matter)
-
You will download a JSON file. Place it in
deploy/<your project>/google-service-account.json
In order to reach out the application from a custom domain name, we should configure it.
-
Go to the Menu, then "App Engine" in "Compute" category, then "Settings"
-
Click "Add a custom domain" and follow the verification process
-
Remove the extra "www." if you are using a subdomain and press "Save mappings"
-
Save the Google DNS zones into your domain name configuration
If you want to enable voice calls, you need to enable the Text To Speech API.
Voice calls generate several files that are exposed on Google Storage in order to limit the number of hits on the app.
-
In the menu, go to Storage under the "Storage" category, and click "Browse".
-
Set a retention policy of 1 day (it's 7 on the screenshot, but don't mind, put 1, at that time I've mixed up with deletion rule)
-
In the menu, got o "IAM & Admin" on Product section, and go to "IAM"
-
Find the service account created for the RedCall app, and click "Edit"
-
Add Storage Object Admin role and click "Save" (note: screenshot is outdated)
-
We now need to configure objects auto deletion: go back to the "Storage" section
In order to delegate sending messages a secure way (with retry, rate limits etc), we need several Cloud Task queues:
Warning: do not copy/paste, the first command will prompt you to enable the API.
# We send 10 sms/second
gcloud tasks queues create messages-sms
gcloud tasks queues update messages-sms \
--max-dispatches-per-second=10 \
--max-concurrent-dispatches=30 \
--max-attempts=100 \
--min-backoff=1s \
--max-backoff=5s
# We send 5 calls/second (warning: Twilio's default is 1, check your Twilio Voice API CPS)
gcloud tasks queues create messages-call
gcloud tasks queues update messages-call \
--max-dispatches-per-second=5 \
--max-concurrent-dispatches=30 \
--max-attempts=100 \
--min-backoff=1s \
--max-backoff=5s
# We can send up to 600 emails/second but don't want to destroy the instance
gcloud tasks queues create messages-email
gcloud tasks queues update messages-email \
--max-dispatches-per-second=500 \
--max-concurrent-dispatches=30 \
--max-attempts=100 \
--min-backoff=1s \
--max-backoff=5s
Check the App\Queues
class for the full list of queues used by the app.
You now need to add few permissions in your service account.
-
In the menu, got o "IAM & Admin" on Product section, and go to "IAM"
-
Add "Cloud Tasks Enqueuer" and "App Engine Viewer" roles, the second one lets the app use an App Engine handler for the tasks.
If you don't want to use GCP, you can set another processor in config/services.yaml, see
in src/Communication/Processor
to see the list of available processors.
Add the following variables in your .env:
GCP_QUEUE_WEBHOOK_RESPONSE='webhook-sms-responses'
GCP_QUEUE_WEBHOOK_STATUS='webhook-sms-status'
GCP_FUNCTION_TWILIO_STATUS=webHooksToTasksSMSStatus
GCP_FUNCTION_TWILIO_RESPONSE=webHooksToTasksSMSResponse
Run gcp/deploy/init/init_api.sh
once per environment.
This will perform the following :
- Enable required APIs
- create a service account and set the appropriate right to run the cloud functions
- create the cloud tasks queues
Then run gcp/deploy/deploy.sh
to deploy the cloud functions
This will perform the following :
- create a temporary directory and copy the sources of the cloud function in it
- update the code with the cloud function name 'webHooksToTasksSMSStatus'
- deploy
- rename again the cloud function name to 'webHooksToTasksSMSResponse'
This creates two endpoint for webhooks that will post on different queues depending it's a SMS status or SMS response from twilio
To run a test (using curl), you can run gcp/test/cloudFunctions/twilioWebhooks/sendPost.sh
This will post sample message with headers to the cloud functions, that should forward this to the AppEngine via Cloud
Tasks