Your First Website on Cycle - Using React and Nginx to Serve a Static Website
Hello! Our blog has moved to our website you can find this article and many others here.
This guide will cover:
- Pulling a ReactJS application from GitHub.
- Packaging that application into a Docker container.
- Pushing the image to DockerHub.
- Importing the image to Cycle.
- Deploying the application and visiting it from the web browser.
Have you set up your first hub on Cycle? If not here’s a video walkthrough to get you started.
But First, Why Containers?
Developing and maintaining software for the cloud has traditionally been a major challenge. We’ve gone from shared hosting, where everything is just installed onto a server at the top level, to Virtual Machines (VMs), where we take a beefy server and chop it up (via software) into smaller, virtualized computers that have a significant amount of isolation built into them, allowing for sharing a server without ever knowing anyone else is running on the same physical machine. Containers are the next step in this evolution.
A container, at its core, is really just a process with some restrictions on it. It runs on the host, but uses features of the Linux kernel to isolate it so that it appears to be the only process running on the machine (among some other isolations, such as network). This is advantageous for a few reasons. First, we get all the benefits of using the host machine — not much overhead, and the container is able to run on the real hardware instead of jumping through virtualized hoops. Second, we get many, if not all of the benefits of virtualization — isolated processes, resource caps, and a sterile, reproducible environment for our applications.
Another premier feature of using containers is the ability to run them anywhere regardless of the underlying OS, packages, versions, or anything else for that matter, whether it’s on your local machine or in the cloud with a platform like Cycle. So this article will not make any assumptions other than:
With Docker, you could buy a computer, install git, a code editor and immediately have a dev environment capable of working with any language.
That's pretty great, so let’s dive right in.
Getting the files
Pull this repo into a new directory (doesn’t matter what it’s named).
This repo is the same collection of files you receive when running the following command, plus a few QOL add-ins:
npx create-react-app appname
There is a file named devscript
included in the repo. To execute this file enter the following into your command line from the applications root directory, ./devscript.sh
. This script builds an image named firstreactapp
using Dockerfile.dev
. It also runs the image with a bind mount on the applications src
directory, allowing for hot reloading*. Take a look inside the script if you want to see the commands I’m running to automate these steps.
* Hot reloading means your application reloads after you make changes to the source without needing to rebuild the image and restart the container.
Hot reload is set up on the src folder, as that's what I make changes to the most during dev. If you make changes to other files, outside of src — just stop the container that’s running with ctrl + c
and run the devscript
again to rebuild the image and restart the container.
Run the devscript
and make any changes you want to the React app. When you’re happy with your app, shut down the development container with crtl + c
.
You’ll need a DockerHub account for this, please visit DockerHub if you don’t already have one set up.
Building the production image
- Move to the root directory of the application.
- Find the file named
Dockerfile
(notDockerfile.dev
). - Open the
Dockerfile
.
The main difference betweenDockerfile
and Dockerfile.dev
is the way we build the container. Dockerfile
uses npm build
to build the source and then uses NGINX to serve the static page(s).
Another big difference between theDockerfile
and Dockerfile.dev
is the two FROM
statements in Dockerfile
. When Docker sees two FROM
statements, it knows that you want a multi-stage build. You can learn more on multi-stage builds here.
Let’s use the Dockerfile
to build our new image.
docker build -t username/firstreactapp:latest -f Dockerfile .
Using the -t
flag with docker build
allows us to name the image in a way that complies with what DockerHub will expect when we need to push to our registry. It’s important to note that the tag latest
is not a part of the image name. It’s actually a tag representing meta information about the image.
You can find more info on tags here.
Using docker run
we can test that our image is working as expected. Use the following command to run the new image.
docker run -p 80:80 username/firstreactapp:latest
Now visit localhost
and see your running application.
Pushing to DockerHub
To log into DockerHub through the Docker CLI, head back to your terminal and enter docker login
. You should be greeted by a dialog asking for your username and password. Entering those credentials will allow you to push and pull images from your DockerHub registry.
Once you’ve logged in, you can run the following command to push the image we just created to your personal DockerHub registry:
docker push username/firstreactapp:latest
Pulling your image to Cycle
So far we’ve created a local development image, made changes to our base application, and built a production ready image that was pushed to your DockerHub registry.
Now we can log into Cycle and pull our image into our Hub.
- Log into your Cycle hub.
- Select “Images” from the left-hand nav.
- Click “Import Image” in the top right corner of the screen.
When importing your image make sure to select “Docker Hub” from the registry options. If you’d like to find out how to create your own private Docker registry using Cycle check out this article.
- In the “Image Name” field, enter your full image name (
username/firstreactapp
). - In the “Tag” field, enter the tag
latest
. - Click “Import”.
When your image finishes importing you can use it to build a container in your environments.
Deploy your image
Create an Environment
If you’ve never created an environment, following this guide can help you get started in just a few steps.
The environment we are going to create today needs to have legacy networking enabled in order to work with the official nginx:latest
image. Legacy networking tells Cycle to enable IPv4 support. Cycle’s native network settings are IPv6 by default, but many apps don’t support IPv6 out of the box. So, it’s simpler to be verbose about the expectations of the environment.
Create the container
After creating your environment, click the blue “Deploy Container” button on the top right of the screen. You’ll be taken to the container wizard where you can describe the settings for the container and tell Cycle which image you want to use.
- In the “Container Name” field enter
firstreactapp
. - The “Stateful” dropdown should be
stateless
. - Leave “Starting Instance Count”, “Deployment Strategy”, “Tags (Any)”, and “Tags (All)” with their default settings.
- Click the “Use Existing” box under “Image” and then use the dropdown menu to select your image.
- Set the “Public Network” field to
Enabled
. - Select “Create Your Container”.
Start the Environment
Now that our container has been created we can navigate back to the environment dashboard and start our environment. To find the environment dashboard click the name of the environment near the top of the page. From here you can start the environment by holding down the start button.
Once the environment is started you can navigate back to the container dashboard and use the domain provided by Cycle to access your container.
Note: When starting your environment for the first time it may take up to 10 minutes for the domain to be recognized by DNS servers, please be patient.
And that’s all it takes to deploy a React application to Cycle! Let’s do a quick recap of what we accomplished.
- Created a development container to work with while we changed our code.
- Created a production container that used a static build of our application and served it with NGINX.
- Pushed the production image to DockerHub.
- Pulled the production image into our Cycle hub.
- Created a container from our image in our environment.
- Viewed our application in a browser using a URL.
Still Have Questions?
If you want to dive in and learn more, head over to our slack channel. Our community is growing, and our team hangs out there daily. Feel free to shoot us a message any time with your questions and we’ll be sure to respond!
Of course, for a more in-depth look at how to use Cycle, check out our documentation.
Learn More + Get Started Today
Thanks for checking out our blog! If you like what you read, please subscribe.
To learn more about Cycle, please visit https://cycle.io.
To create a free account, check out our portal!