Skip to content

Commit

Permalink
feat(render): add deployments section
Browse files Browse the repository at this point in the history
  • Loading branch information
jslvtr committed Aug 24, 2022
1 parent 978213c commit 4240662
Show file tree
Hide file tree
Showing 18 changed files with 183 additions and 3 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ __pycache__/
*.db
.DS_Store
venv/
.venv/
.venv/
docs/docs/.nota/config.ini

This file was deleted.

1 change: 0 additions & 1 deletion docs/docs-upcoming/10_deploy_to_render/README.md

This file was deleted.

13 changes: 13 additions & 0 deletions docs/docs/11_deploy_to_render/01_section_overview/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Overview of this section

In this section, we will figure out how to get our Flask app and put it on a public server so other people can interact with it! This is called "deploying".

There are many services we can use to deploy our app. Most of them have some sort of "free tier" so that you can try the deployment without having to pay anything. Usually, if you want better performance or unlimited usage, you have to pay.

Remember that just as we run the Flask app in our computers, when we deploy it the app runs in a server, somewhere in the world. For all intents and purposes, the server is just like our computer!

Servers usually run Linux, so we can deploy our Docker images without a performance hit as we would using Mac or Windows.

At the end of the section, you'll be able to access your API using a URL such as [https://rest-api-smorest-docker.onrender.com](https://rest-api-smorest-docker.onrender.com).

For this section, our deployment will be completely free. We will deploy our Flask app for free, and we will also get a free PostgreSQL database on the cloud using ElephantSQL.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Creating a Render.com web service

Let's start by going to [https://render.com](https://render.com) and signing up to an account. You can "Log in with GitHub" to make things easier.

Once you've logged in, you'll see in your [Dashboard](https://dashboard.render.com/services) that you can create a new service using a button at the top right of the page.

Click it, and select "Web Service".

Options other than "Web Service" are useful for different kinds of applications, and some are databases that you can use (but not for free, so we won't use Render for our database in this section).

Then you'll [connect your GitHub account](https://render.com/docs/github) if you haven't already, and look for your repositories.

Select the repository that you created during this course:

![Render.com screenshot showing how to search for and select a repository to connect to from GitHub](./assets/render-github-connect.png)

Then, give it a name and make sure the configuration is as follows:

![Render.com screenshot showing the web service configuration](./assets/render-service-config.png)

- Make sure "Docker" is selected.
- Select a server location close to you. I'm near Frankfurt, but if you are in the US or Asia you might want to choose a different one so it's faster to connect to.
- Select the "Free" server option.

At the bottom of the service there is an "Advanced" section which you can use to further configure your service. We'll talk more about that in a bit.

For now, hit "Create Web Service" and wait for it to deploy your code from GitHub!

If you navigate to your Dashboard and then click through to your newly created service, you'll be able to see the service details. If it isn't already deploying, click on the "Manual Deploy" button on the top right to initiate a deploy of the latest commit:

![](./assets/deploy-latest-commit.png)

Then you should start seeing logs appear detailing the deployment process!

![](./assets/render-deploy-screen.png)

While on the free plan, deployments are a bit slow. It has to build your image and run it! Give it a few minutes, until the deployment succeeds. You should see this:

![](./assets/render-deploy-finished.png)

Now, you can access your service URL and try it out using Insomnia or Postman!

![](./assets/insomnia-test-prod.png)

:::warning
Free services in Render.com shut down after inactivity for a few minutes. If you don't use your service for a few minutes, it will shut down and it will need to restart, which can take a minute! This is one of the limitations of their free plan.
:::
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# How to get a deployed PostgreSQL database for our app

There are many PostgreSQL-as-a-Service providers (that means, services that handle creating and maintaining your database for you).

Render.com offers PostgreSQL, and the pricing is actually quite fair. However, the free tier is limited and you can only use it for a certain amount of time.

That's why I recommend using ElephantSQL for your free PostgreSQL needs. When you go over the free ElephantSQL limits, then you can use the Render.com database instead.

To get a free ElephantSQL PostgreSQL database, just go to their site, sign up, and then create a database in a region close to your Render.com server. Make sure to select the free tier.

![ElephantSQL screenshot showing plan configuration of Tiny Turtle (free) and name](./assets/select-plan-and-name-elephantsql.png)

Once you've got this, you should be able to see the Database URL:

![ElephantSQL screenshot showing that a copy icon beside the Database URL can be clicked to copy it](./assets/copy-elephantsql-url.png)

Copy this, as you'll need it in the next lecture!
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
104 changes: 104 additions & 0 deletions docs/docs/11_deploy_to_render/04_environment_variables/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# How to use Environment Variables in Render.com

A common way to configure applications before they start up is by using environment variables.

We can define environment variables in our computers, and also in our servers, and of course they can be different in each.

That's what's interesting about them: we can define an environment variable locally for our database, which may be `sqlite:///data.db`. Then in our server we can define the same variable, but with a value of the ElephantSQL Database URL.

Since we are using SQLAlchemy in our application, it doesn't care whether it's connecting to SQLite or PostgreSQL. So all we have to do to use a different database is change the connection string.

Let's begin by using environment variables locally.

## How to use environment variables locally with our Flask app

First, let's create a new file called `.env`. In this file, we can store any environment variables we want. We can then "load" these variables when we start the app.

```text title=".env"
DATABASE_URL=sqlite:///data.db
```

With the file created, we can load it when we start our Flask app:

```python title="app.py"
# highlight-start
import os
# highlight-end
from flask import Flask, jsonify
from flask_smorest import Api
from flask_jwt_extended import JWTManager
# highlight-start
from dotenv import load_dotenv
# highlight-end

from db import db
from blocklist import BLOCKLIST

from resources.user import blp as UserBlueprint
from resources.item import blp as ItemBlueprint
from resources.store import blp as StoreBlueprint
from resources.tag import blp as TagBlueprint


def create_app(db_url=None):
app = Flask(__name__)
# highlight-start
load_dotenv()
# highlight-end
app.config["API_TITLE"] = "Stores REST API"
app.config["API_VERSION"] = "v1"
app.config["OPENAPI_VERSION"] = "3.0.3"
app.config["OPENAPI_URL_PREFIX"] = "/"
app.config["OPENAPI_SWAGGER_UI_PATH"] = "/swagger-ui"
app.config[
"OPENAPI_SWAGGER_UI_URL"
] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist/"
# highlight-start
app.config["SQLALCHEMY_DATABASE_URI"] = db_url or os.getenv("DATABASE_URL", "sqlite:///data.db")
# highlight-end
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["PROPAGATE_EXCEPTIONS"] = True
db.init_app(app)
api = Api(app)
```

Highlighted are four lines which we must change.

1. First we `import os`. We'll need this to access environment variables.
2. Second, we import the `load_dotenv` function, which we'll need to run in order to turn the contents of the `.env` file into environment variables.
3. We actually run the `load_dotenv` function.
4. We'll use `db_url` if provided, otherwise we'll retrieve the environment variable's value. If there is no environment value, the default will be `"sqlite:///data.db"`.

Notice that our Flask app has two ways to be configured: with the `db_url` argument, or via environment variables. You would normally use `db_url` when writing automated tests for your application. While we don't do that in this course, it's a good habit to get into!

:::warning
Do not include your `.env` file in your GitHub repository! Add it to `.gitignore` so you don't include it accidentally.
:::

Since we can't include `.env` in our GitHub repository, we should do something to make sure that new developers know that they should create a `.env` file when they clone the repository.

We normally do this by creating a file called `.env.example`. This file should only contain the environment variable definitions, but not the values:

```text title=".env.example"
DATABASE_URL=
```

You should add `.env.example` to your repository.

Commit the changes, and push them to GitHub. We'll need these changes so we can use environment variables in Render.com.

## How to add environment variables to Render.com

Now that our Flask app is using environment variables, all we have to do is add the `DATABASE_URL` environment variable to our Render.com service, and then deploy the latest changes from our GitHub repository.

To add environment variables in Render.com, go to the service settings and then on the left you'll see "Environment":

![Render.com screenshot showing the button to add a environment variables](./assets/render-add-env-var.png)

Click on "Add Environment Variable", and there put `DATABASE_URL` as the key, and your ElephantSQL Database URL as the value:

![Render.com screenshot showing DATABASE_URL added with a pixelated value](./assets/render-database-url-env-var.png)

Now, do another manual deploy of the latest commit (which should include your `app.py` changes to use environment variables).

When this is done, your app should be saving to the ElephantSQL database!
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 4240662

Please sign in to comment.