Digital Ocean App Platform Hackathon: Using Non Natively Supported Platforms (Rust + Rocket)
Tags: dohackathon, rust, tutorial, beginners
Published: 2020-12-14 11:58:10

[<span>Photo by <a href="https://unsplash.com/@marcobian?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Marco Bianchetti</a> on <a href="https://unsplash.com/s/photos/shipping-container?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></span>, modified (cropped)]

**DISCLAIMER**: The following might require you to spend some money on the DigitalOcean platform. 

However, in the [repo](https://github.com/davidedelpapa/do-apps-rust-example) and here, I have set up a `Deploy to DigitalOcean` button that lets you try the finished app, and guides you to registration on DigitalOcean, if you did not register yet, and gives you some money buffer for 60 days to try DigitalOcean's products.

The button has a referral code as well, so tht you can have a money buffer to try DO products, and I can have some coffee (I hope). Yet **you are free to try all this without touching that button**; you just need to [subscribe to Digital Ocean](https://www.digitalocean.com/) (but you won't get any trial money buffer in that case).

## Introduction

The new [Digital Ocean App Platform Dev.to Hackathon](https://dev.to/devteam/announcing-the-digitalocean-app-platform-hackathon-on-dev-2i1k) has just started. However, while there is a big amount of documentation (and growing) out there, on how to start to use this wonderful new tool, much is lacking if you want to use unsupported languages.

Therefore this tutorial is trying to fill in the gap, providing a gentle introduction on how to deploy not natively supported apps.

### Plan of Action

Digital Ocean does support a lot of programming languages, but still, it does not as yet provide support for interfacing any chosen language. So, how would we go about and deploy an unsupported language nevertheless?

Well, Digital Ocean's App Platform supports [Docker](https://www.docker.com/): this will be our way to "smuggle in" an unsupported language, let's say, [Rust](https://www.rust-lang.org).

The plan is this: we will fork Digital Ocean's docker repository, then personalize it, and finally deploy it.

### How to Follow the Tutorial Even Without Installing Rust

The following implies that you have on your system a valid Rust installation ([More info here, the official Rust installation page](https://www.rust-lang.org/tools/install)).

However, it is not needed that you have Rust installed on your system. If you don't want to install Rust, bust still you want to use it, just use [my repo](https://github.com/davidedelpapa/do-apps-rust-example) as a template (green button top, near the cloning URLs), instead of forking Digital Ocean's docker repository. 

Then start to follow from the section called **Try Locally the App**.

In fact, we will use Rust inside an image to compile the app.

**Notes: you must have however a working Docker installation on your system to follow this tutorial. That is needed to check the installation**

## Fork and Make It Your Own

Go to: [github.com/digitalocean/sample-dockerfile](https://github.com/digitalocean/sample-dockerfile)

![Fork the repo](https://dev-to-uploads.s3.amazonaws.com/i/qgktvy8svcaoqwxixfqf.jpg)

Fork the repo.

![Fork done](https://dev-to-uploads.s3.amazonaws.com/i/g5otgkt539uk3sftoc2o.jpg)

Now you need to go to your forked version (GitHub automatically redirects to it, once the forking process is completed) and rename the repo (under the Setting tab)

![rename the repo](https://dev-to-uploads.s3.amazonaws.com/i/xpy7r7tdkvxlwv33sogw.jpg)

It is now time to clone the repository on your machine. Go to the shell:

```sh
git clone https://github.com/<your-account-name>/<your-project-name>.git
cd <your-project-name>
```

Now we need to create a Rust project (you can get rid of the two GO files, namely *go.mod* and *main.go* if you want).

## Simple Rust App

On the shell, inside the repository root, give the following command:

```sh
cargo init --name myapp
```

Now we have a *Cargo.toml* file and a *src/* folder (plus a *.gitignore* file).

We should also set the nightly toolchain:

```sh
rustup override set nightly
```

There we go, we are ready to develop a Rocket app.

If you do not have it installed, I recommend a little, useful tool: [cargo edit](https://crates.io/crates/cargo-edit); with it we can even script most of the setup for a new cargo project. To install it, just run:

```sh
cargo install cargo-edit
```

Now we can add dependencies from the command line (and from make, shell scripts, Dockerfile, etc):

```sh
cargo add rocket
```

Let's change now the *main.rs* file inside *src/*

### src/main.rs

Change the content of *src/main.rs* to match the following:

```rust
#![feature(proc_macro_hygiene, decl_macro)]
use rocket::*;
use rocket::response::content::Html;

#[get("/echo/<echo>")]
fn echo_fn(echo: String) -> String {
    format!("{}", echo)
}

#[get("/")]
fn hello_fn() -> Html<String> {
    Html("<h1>Hello, world!</h1><p>From inside a DigitalOcean App</p>".into())
}

fn main() {
    rocket::ignite().mount("/", routes![echo_fn, hello_fn]).launch();
}
```

In the above we created two routes, a `echo` route, that re-prints everything is passed to it after a slash `/`, and a `hello` route, that greets with the usual `hello, world`. This last is placed as the root of the server.

## The Dockerfile

Now we usually would compile and run the above with a `cargo run` (and you can still give it a try, to make sure there were not errors in the code). 
However, this time we have to make sure we are able to do it from inside a docker container.

We need to change the *Dockerfile* of the project. It must look like the following:

```dockerfile
FROM rust:1.40 as builder
WORKDIR /usr/src/myapp
COPY . .
RUN rustup override set nightly; \
    cargo install --path .

FROM debian:buster-slim
COPY --from=builder /usr/local/cargo/bin/myapp /usr/local/bin/myapp
ENV ROCKET_PORT 8080
CMD myapp
```

The above implies a current version of docker installed in your system. If not, please follow the instructions below:

[docs.docker.com/get-docker/](https://docs.docker.com/get-docker/)

There you can find instructions for various operating systems.

## Try the App Locally

Before deploying to Digital Ocean, let's build this on our machine:

```sh
docker build --tag myapp .
```

(take care there's a dot at the end of the above command!)

Then, we can run it with:

```sh
docker run --rm --network="host" -id myapp
```

The above should give you a hash that represents the running container. Keep it for later, because to halt the container after use, you may run:

```sh
docker kill <container-id>
```

Still if you forgot, you can get the id (a shorter yet usable one) with `docker ps`.

To test the container while running, point your browser to `localhost:8080` (with the `--network="host"` we connected the docker's own `localhost` with the host machine's one).

![Our app running](https://dev-to-uploads.s3.amazonaws.com/i/4mwxhk2oqgmm1xqz52vl.jpg)

When we are satisfied we can shut down the image (`docker kill`) and go to the next step.

## Deploying our image to DigitalOcean's App Platform

First we have to commit our repo to GitHub:

```sh
git add -A 
git commit -m "First Rust Commit"
```

Then you can push to `main` (the `master` replacement).

```sh
git push origin main
```

Now we can go to [DigitalOcean's App page](https://cloud.digitalocean.com/apps).

If you did not register as yet, you have to do so before this step.

*Small Ad Note*: You might use the `Deploy on DigitalOcean` button on my repo, that lets you try the final app and gets you a credit for 60 days to get you some $ to try the app without spending any $ (**DISCLAIMER**: It has a referral code so while you get the free credit for 60 days as trial period I should get something as well, qui pro quo I suppose).

If we do not have any deployment so far we are greeted with an action button: `"Let's build something"`.

![Deploy GitHub Repo](https://dev-to-uploads.s3.amazonaws.com/i/gb2scb1hsl4zp44kl56q.jpg)

We go at the end of the list and select the `Deploy a GitHub Repo`. This will prompt the Apps Panel.

![App panel](https://dev-to-uploads.s3.amazonaws.com/i/wgjzpfi6483r24khcdt7.jpg)

Clicking on the `Launch Your App` button will start the procedure to allow DigitalOcean to `Link Your GitHub Account` if it is the first time. Just follow the procedure.

At the end of the procedure, the page will ask you to select a repository.

![Select a Repo](https://dev-to-uploads.s3.amazonaws.com/i/6137f6shdvt5r4hb56y9.jpg)

Then you will be prompted with the options for the name, the branch and the region of deployment

![App Options](https://dev-to-uploads.s3.amazonaws.com/i/1xiwsbokom8tr04x2o57.jpg)

Then you will be asked some configuration info: since there's a `Dockerfile` it will automatically detect everything. 

![App Configuration Options](https://dev-to-uploads.s3.amazonaws.com/i/n3t6cqln3ul0qe9zmgwy.jpg)

Then you have to select your plan: the starter (free) plan is only for static sites, so it is unavailable. 

![Select a Plan](https://dev-to-uploads.s3.amazonaws.com/i/44du1mdpppwj0oahlsz6.jpg)

However, make sure at the bottom of the page to select the *512 MB RAM, 1 CPU* container, that is the 5$/Month option (not selected by default). This will take some more build times (to me it took a good 12 minutes), but it still works.

![Select Cheapest Plan](https://dev-to-uploads.s3.amazonaws.com/i/i9icp72jjwbu3zurfgfj.jpg)

Now you can launch your app (`Launch Basic App` button, bottom right).

![Build the App](https://dev-to-uploads.s3.amazonaws.com/i/xyyh82gv40mcg588ufdw.jpg)

At the end of the procedure you will get a success banner with a link to the *Live App*

![Success Banner](https://dev-to-uploads.s3.amazonaws.com/i/92xwr1qov0ey1xitjx59.jpg)

Yatta! We made it!

![Live Running App](https://dev-to-uploads.s3.amazonaws.com/i/j2b7kj7qqr1y76b9nb4m.jpg)

You can check the *echo* route as well:

![Live Running App: Echo Route](https://dev-to-uploads.s3.amazonaws.com/i/xuiog8587fz3nyyc4ava.jpg)

Everything works like a charm.

### Quick Troubleshot 

It might happen (to me it did) that Digital Ocean gives some random error at the very first attempt, and the build fails.

Since the app is rebuild after each commit, even changing a little thing in the *README.md* will trigger a new build; so, you can change some unimportant thing, commit, and the build will restart. If it fails again, then probably the error is more serious, or maybe there's a bug or a typo somewhere in the code, and you should take action.

In this case consider cloning my repo altogether, and try deploying it (or use the `Deploy to DigitalOcean` button).

## Deleting the App

When you finish to try it and make some changes, if you do not need it anymore, you can delete the app by following these steps (the following is taken from DigitalOcean's own repo, so I guess it is important!):

1. Visit the Apps control panel at https://cloud.digitalocean.com/apps
2. Navigate to the do-apps-rust-example app
3. Choose "Settings"->"Destroy"
4. A confirmation message will be prompted, where you have to re-insert the name of the app (to make sure it was not done by mistake)

This will delete the app and destroy any underlying DigitalOcean resources

**Note: If you don't delete your app, charges for the use of DigitalOcean services will continue to accrue.**

## Conclusions

We have seen how to deploy non natively supported languages (Rust in this case) to DigitalOcean's App Platform, by using the supported Docker images.

Now you can participate to the  [Digital Ocean App Platform Dev.to Hackathon](https://dev.to/devteam/announcing-the-digitalocean-app-platform-hackathon-on-dev-2i1k) also using Rust.

If you want to set up an API with Rust, I am currently holding a [series on Rocket](https://dev.to/davidedelpapa/rocket-tutorial-01-basics-4ph9), and the first tutorials deal with the API world. It covers the basics, integration with MongoDB or Redis, and more is coming.

Stay healthy, stay tuned!