-
-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This changes the following: 1. Move all deployment related guides (Previously Netlify and Render) under a "Deployment" section 2. Add some notes on what deployment is, what free options there are and what the limitations of each of these options are 3. Adds section for fly.io deployment 4. Adds section for backend deployment on Netlify (this links to code that is on my GitHub account - will move to CYF once the Full Stack assessment reorg is done) 5. Adds section for registering for Supabase
- Loading branch information
Showing
83 changed files
with
614 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
--- | ||
id: deployment | ||
title: Deploying applications | ||
emoji: 🖥️ | ||
--- | ||
|
||
# What is deployment? | ||
|
||
Deploying in short is making sure the application you are developing is made available for the world wide web to see (or in case for internal systems it is at least visible to the intended audience). Without the ability to deploy the only way to show what you have done is ask others to come to your computer, and show them the work on it in person. | ||
|
||
{{<note type="note" title="TL;DR">}} | ||
The CYF Curriculum team suggest [Netlify]({{< ref "/guides/deployment/netlify" >}}). as a free provider to use for both your frontend and backend applications, with Supabase as a free database layer for persistence. This is because among the free tier offerings they have the least amount of limitations. | ||
|
||
This suggestion assumes that you are interested in a fully free option, and you can accept the limitations. If you have a deployment budget for your work and/or the limitations are not acceptable you are free to look at other choices as well. | ||
{{</note>}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
--- | ||
id: application_stack | ||
title: The application stack | ||
weight: 3 | ||
emoji: 🖥️ | ||
--- | ||
|
||
# The application stack | ||
|
||
In the previous section we talked about the fact that most full-stack web applications have multiple layers (generally at least a frontend and a backend component and some kind of persistence layer in form of a database). In this section we go through these layers and talk about how they are usually deployed. | ||
|
||
## Frontend | ||
|
||
In the curriculum we teach, frontend files are considered static. What this means is that once you deploy them, they will never change until the next deployment comes. Your `index.html`, `index.js` files, your CSS files and your image assets will always contain the same content regardless how many times they are downloaded and shown in browsers around the world. | ||
|
||
This makes them an ideal candidate to serve them through CDNs, Content Delivery Networks. These systems deploy your static files around the globe allowing people to access them quickly. Serving static files are fairly inexpensive, as you only need disk space and bandwidth, so a lot of companies provide this for free for small projects and you only need to pay once your user count becomes large enough. | ||
|
||
CloudFlare Pages and Netlify are some examples of CDN providers that have generous free tiers allowing you to host your static files with them. GitHub Pages, while not strictly considered a CDN, also allows you to host files from your repository in a simple way. | ||
|
||
{{<note type="warning" title="Other frameworks">}} | ||
Do note that while the fact that frontend files are static is true for the frameworks we teach, it is not universally true for all frameworks. Web focused languages like PHP, and MVC frameworks like Ruby on Rails or Django, allow you to create dynamic frontend files. Some React frameworks also support server-side rendering which can make the frontend part of your application dynamic, and ineligible to be served through CDNs. Anything static, like CSS files or images however you can still serve through CDNs, and it is generally still a good idea to do so to improve your application's loading speed. | ||
{{</note>}} | ||
|
||
CDNs are however not the only way to deploy and serve your frontend. You can also add code to your backend server that will enable it to serve your static files. This allows you to use any of the backend providers (that support persistent deployments) to serve your frontend as well. Main benefit of this approach is that your frontend and backend parts remain closely tied together, you can for example easily deploy them at the same time making sure there are no version discrepancies between the two. However you would lose the benefits of CDNs, and although serving static files are not computationally too involved they still need to be handled, which will in turn slow down your backend. | ||
|
||
## Backend | ||
|
||
In contrast to the frontend, your backend systems are almost always considered dynamic. Every request they receive they need to generate a response on the fly based on the request and usually the contents of the database. This means deploying backends are much more involved, and this shows in free offerings as well - there are less options to host your backends for free, and the ones that are available have hefty limitations, forcing you to pay for an upgrade. | ||
|
||
To deploy your backend there are generally two wide categories of deployment mechanisms: persistent and serverless. | ||
|
||
### Persistent deployment | ||
|
||
In persistent deployment scenario you run your backend server all the time. This is very similar how you usually run your backend during development on your local computer. This allows you to fully utilize the features of your backend framework, including features like backend workers. Latency - the time needed for your server to respond - is usually quite low compared to serverless deployments. | ||
|
||
Biggest drawback is that running a server constantly is more expensive, therefore free tiers are in very limited supply. Glitch, Render and Fly.io are some providers that still offer this, but all of them have strict limitations: the first two will for example stop your server if it doesn't receive activity for a longer time. This will make your service be very-very slow whenever it needs to be restarted. | ||
|
||
Apart from the providers above persistent deployment is what people usually use VPS providers for, and the big players usually have a free tier available. AWS's EC2, Azure's Virtual Machines and Google's Compute Platform all have a one year time limited trial that allows you to use their slowest computer for free. However because neither of these services support automated deployments out of the box, and it is very easy to accidentally overshoot the trial package (for example by accidentally starting up a slightly larger computer than the slowest one) we don't recommend any of these options for the projects we do in the curriculum. | ||
|
||
### Serverless deployment | ||
|
||
Serverless, sometimes called on-demand, functional or lambda deployments mean that your server is not running constantly. Whenever there is a request the serverless provider will start up your backend, let it serve the request and then stop it immediately afterwards. | ||
|
||
Benefits of this approach is that your service doesn't consume resources unless it's used. It is usually aimed for systems that are either not used constantly, or where there are periods of high usage, which needs more resources to handle. Running your backend on-demand only is also less expensive, so there are more free options available to use. | ||
|
||
Drawbacks of this approach is that your server is getting started and stopped all the time, so it needs to be developed in a way to make this less of a problem. Unfortunately Express.JS is not designed with serverless operation in mind, bot there is a plugin to allow its core functions to operate. However anything that requires your system to run constantly, including global variables or backend workers will not work, and need to be replaced with an alternative. Also the constant starting and stopping is slow therefore serverless functions have a higher latency than persistent servers. | ||
|
||
Netlify Functions, Cloudflare Pages, Supabase Functions are some examples that have free tiers available, and big players like AWS's Lambda also provide support for this in their time limited free tier. | ||
|
||
## Database | ||
|
||
The final part of a full stack application is the persistence layer, which is usually a database, in our current curriculum likely a relational database, like Postgres. | ||
|
||
It's not the only kind of data store that you might need. For example if your application needs to support file uploads and you need to store those files somewhere you would need to opt in for some kind of file storage server as well, this is outside of the scope of this guide however. | ||
|
||
Free Postgres databases are offered by Supabase, Fly.io and Render with some limitations. Other kind of SQL databases are available from Cloudflare and are present inside the free tiers of AWS, Azure and GCP. These offerings do not follow Postgres' SQL standard we teach however, so are outside of the scope of this guide. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
--- | ||
id: deployment_strategies | ||
title: Deployment strategies | ||
weight: 4 | ||
emoji: 🖥️ | ||
--- | ||
|
||
# Deployment strategies | ||
|
||
In the previous section we went through where you can deploy your application. In this guide we will go through how to do that. | ||
|
||
## Manual deployment | ||
|
||
Manual deployments are when you need to take an action yourself to get your application deployed. This can be anything from running a couple of commands to needing to press a button on a website. | ||
|
||
For example in the scenario where we imagined that you have both a development computer and a small server in your house, deploying your latest version manually could be following the steps below: | ||
|
||
1. Commit your changes and push them to the `main` branch on the development machine | ||
2. Login onto your server computer | ||
3. Go to the running application's directory | ||
4. Stop the application | ||
5. Pull the latest changes from the `main` branch | ||
6. Run `npm i` | ||
7. Start the application again | ||
|
||
Manual deployments done in a way above can be error-prone. For example if you forget to do step 7 your application will not be running at all at the end. If your provider does not support built-in automated deployments it is usually advised to create scripts that would do all of the steps above, so any time you wish the latest version to be deployed you would just need to run the script. Scripts can fail so you would still need to make sure to check the logs and see if everything went as expected. Trying to access your website after deployment is also a good way to check that everything is in order. | ||
|
||
## Automated deployment | ||
|
||
Automated deployment or Continuous deployment is whenever your code changes, the deployment flow is initiated automatically. For example any time your code ends up in the `main` branch of your GitHub repository deployment will commence automatically, and your code will end up on your servers. You can imagine this by someone automatically running the deployment script we've created above whenever your repository changes. | ||
|
||
Some frontend and backend providers have GitHub integration and will support automated deployments out of the box. For others, you either need to deploy manually by following a set of steps, or automate these manual steps by creating GitHub workflows manually. | ||
|
||
## Pull Request checks | ||
|
||
While automated deployments might sound scary, for example if you make a mistake in your code automated deployments would deploy that mistake automatically. There are ways to mitigate these risks by adding checks that run after each pull request is created, blocking merging if they fail. Common checks include linting, that would make sure that your code adheres to good coding conventions. Other checks that you can include are running unit, integration and end-to-end tests for each PR making sure that the code you've done passes these requirements. | ||
|
||
## Snapshot builds | ||
|
||
Another feature that helps make automated deployments less risky are snapshot builds. These are a feature of some providers where they not only deploy your `main` branch, but also deploy your other branches as well in a temporary fashion. For example if you create a new pull request from branch `new-awesome-feature` the provider will deploy this branch separately to your production environment. This will allows you, and anyone assessing your pull request to check how your changes would look like before actually merging them. | ||
|
||
Not all providers support snapshot builds. For the ones that do not, a common way to mitigate this is to set up two sets of servers, one called *production* while the other *staging* (other common names for this second set are *pre-production* or *sandbox*). You would then deploy to this environment first, and only after checking that it works as expected continue the deployment to *production* one. Do note that this usually requires you to set up your environment multiple times, and this will also increase the cost of your setup. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
--- | ||
emoji: 🚀 | ||
title: Deploying to Fly.io | ||
description: Learn how to deploy your website to Fly.io | ||
weight: 8 | ||
--- | ||
|
||
[Fly.io](https://fly.io/) is a provider allowing you to deploy backend applications that are converted into docker containers. It also allows one to start up a small PostgreSQL database on their system. By making sure that the [frontend is served through the backend]({{< ref "/guides/deployment/flyio/serving-frontend" >}}) you can therefore easily deploy your entire stack on fly.io. | ||
|
||
The main drawback of fly.io that it's free trial only allows you to deploy exactly two systems. For a full stack application this would be the backend (which is also serving the frontend), and the database, meaning you would only be able to deploy a single project freely. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
--- | ||
emoji: 🚀 | ||
title: Accessing fly.io databases | ||
description: Learn how you can access the fly.io PostgreSQL database | ||
weight: 3 | ||
--- | ||
|
||
## Accessing database | ||
|
||
If you have been following the setup guides you would have both a backend and a database system running under fly.io. | ||
|
||
Your database can hold data for multiple applications, so first you need to get a list of them: | ||
|
||
```bash | ||
flyctl postgres db list -a YOURNAME-PROJECTNAME-db | ||
``` | ||
|
||
(Make sure you use your database's name after the `-a` that you have set up before) | ||
|
||
On the list you will find under the NAME column three values: `postgres`, `repmgr` and finally the name of your application's datastore. It will be something like `YOURNAME_PROJECTNAME` - same as your application name but all of the dashes are replaced with underscores. | ||
|
||
Take a note of this name as you will need it later. | ||
|
||
## Uploading database | ||
|
||
To connect to the database you will need to use `flyctl`: | ||
|
||
```bash | ||
flyctl postgres connect -a YOURNAME-PROJECTNAME-db -d YOURNAME_PROJECTNAME | ||
``` | ||
|
||
Where the first value is the name of the database you set up in level 150, and the second value if the datastore name you obtained in the last section. | ||
|
||
The command above will start you up with a proper `psql` console where you can run commands. | ||
|
||
You can also pipe in SQL files. For example if you have an `initdb.sql` file containing SQL commands to initiate a database you can do: | ||
|
||
```bash | ||
flyctl postgres connect -a YOURNAME-PROJECTNAME-db -d YOURNAME_PROJECTNAME < initdb.sql | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
--- | ||
emoji: 🚀 | ||
title: Serving frontend from your backend | ||
description: Learn how to add support for serving frontend files to Express.JS backends | ||
weight: 2 | ||
--- | ||
|
||
Fly.io doesn't have a built-in CDN for serving static frontend files directly, so if you wish to deploy your frontend you need to do it through your backend. | ||
|
||
Express.JS has fortunately a built-in middleware just to do that. You only need to set the location of your frontend files, and it will take care of serving the contents for you. | ||
|
||
For example if you add the following middleware inside your `/server/app.js`: | ||
|
||
```js | ||
const staticDir = path.join(__dirname, "..", "static"); | ||
app.use(express.static(staticDir)); | ||
``` | ||
|
||
Then anything under the `/static` directory will be served as-is. | ||
|
||
{{<note type="warning" title="TL;DR">}} | ||
Express.JS will not compile these files for you, so if you have Javascript files that need compilation, like React JSX files you need to do that separately. | ||
{{</note>}} | ||
|
||
If you have a React application and you wish it to support React Routes you also need to make sure that every request that doesn't correspond to a real file gets routed to your main website. You can do that with adding a code like the following: | ||
|
||
```js | ||
app.use((req, res, next) => { | ||
if (req.method === "GET" && !req.url.startsWith("/api")) { | ||
return res.sendFile(path.join(staticDir, "index.html")); | ||
} | ||
next(); | ||
}); | ||
``` | ||
|
||
This will point any request that was not yet handled in a previous middleware, and are not starting with `/api` to your `index.html` allowing React Router to handle it internally. | ||
|
||
You can find a full `app.js` example showing static file serving [here](https://github.com/sztupy/Full-Stack-Project-Assessment/blob/main/server/app.js). |
Oops, something went wrong.