Hybrid - Docker + Static Site Example

Overview

This is an example of a more complex application that contains both a set of Docker services and a static Javascript SPA that connects to the Docker services all within a standalone Release environment.

Fork the repository on Github

  1. On Github, navigate to the github.com/awesome-release/react-express-mysql repository.

  2. In the top-right corner of the page click Fork.

Login to Release and refresh your list of repositories

  1. Login to your Release account.

  2. Click Create New Application on the left hand sidebar.

  1. Refresh your repositories by clicking on the circle on the right hand side of the list of repositories

  1. Select the react-express-mysql repository and use the default "main" branch.

Release will analyze and detect the different service types. When there is ambiguity and it's possible to use more than one service type, then you will have to manually choose which type you prefer. You should see:

  • backend - Docker service type

  • db - Docker service type

  • frontend - no service type selected yet

The frontend service can be deployed with both Docker or Static in this case so it will not default to either one. To illustrate how we can deploy a hybrid Docker + Static application, we will have the backend & db use Docker, while frontend will be Static.

  1. Select "Static" for the frontend service. The backend & db Docker services don't require any parameters during setup as Release infers the setup from the docker-compose.yaml file found in the repository. The frontend service, when set to "Static", requires build parameters that are automatically detected out of the package.json file within the repository. For more information read Static Service Deployment on building and deploying static services. In this case Release detected the frontend service in the "frontend" directory, it will be built with the "yarn build" command and the build files will be copied into the "build" directory.

After selecting Static frontend service type, build command will appear.
  1. At this point, you may modify the application name or use the default, which is the name of your repository. Click the "Generate App Template" button to proceed.

  2. View the Application Template and modify if necessary. If you aren't familiar with this Release concept yet, it's a good idea to review the documentation to understand how the template is used to initialize your application and any subsequent environments that are generated from it. Click "Save & Continue" to move to the next step.

Application Template Example
  1. The final step in app creation is adding any Build Arguments, Default Environment Variables, or Just-in-time File Mounts if necessary. More advanced applications may require these features, but for this example, we can skip ahead. If you think your application will require one of these features, feel free to pause and check out the documentation at this time. Click on "Start Build & Deploy" to proceed.

  1. While Release is building and deploying the hybrid app, you will be directed to the Application Dashboard where you can see an Activity log with your environment. You can navigate around to Builds or Deploys to view status logs of your application.

Application Dashboard Example

Once the Environment is completed, go ahead and click on it to see the details.

Environment Details Example

If you scroll down further, you'll see a section title "Instances", shown below.

You can see that the environment deployed successfully, all services are running and both the frontend and backend URL's are live. However, the application isn't communicating from the frontend to the backend. You can see this issue by clicking on the frontend URL and inspecting the network traffic on the page.

In order to understand why this is happening, we must look at the frontend code where it's attempting to fetch data from the backend. Here is a snippet of the frontend code where this is happening.

function App() {
const [message, setMessage] = useState();
useEffect(() => {
fetch(process.env.REACT_APP_BACKEND_URL)
.then(res => res.json())
.then(res => setMessage(res.message))
.catch(console.error);
}, [setMessage]);
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>{message || "Loading..."}</p>
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}

This snippet is taken from App.js here: https://github.com/awesome-release/react-express-mysql/blob/main/frontend/src/App.js‚Äč

You can see on line 4 above, the fetch is attempting to pull data from an environment variable set by React labeled REACT_APP_BACKEND_URL This environment variable is intended to hold the URL of the backend service. However, since URL's are dynamic in Release, this URL is not accessible just yet and we need to apply an environment variable mapping in the configuration of this environment.

In order to set this mapping, we must edit the environment variables for this environment and set a mapping. On the Environment Details screen, navigate to the Settings tab and click on the Edit button for Environment Variables.

Environment Details | Settings Tab

This will open the Environment Variables Editor where we need to add a mapping to this file.

Here we have added lines 2 and 3. These lines instruct Release to map REACT_APP_BACKEND_URL to the dynamically created BACKEND_URL_INGRESS variable that is dynamically set to the backend service for this application. Once you have made this edit, click SAVE AS NEW VERSION.

We can see that a new version of the environment configuration has been saved, but not yet deployed.

To apply the latest version changes, click APPLY at the bottom under Apply Latest Configuration section. This will kick off a deploy of the latest configuration and set the environment variable mapping.

Once the deploy has finished, click on the Environment name and go back to the Settings tab. You can now see that the latest environment configuration version 1.2 matches the currently deployed environment configuration version. Read more about environment versioning.

Go back to the Details tab where you can find the Hostname URLs section. Click on the frontend url hostname to view the deployed preview environment.

In the browser you should see "Hello from MySQL" style message render. You can go back into network inspection and verify. You can now see the frontend service is now correctly communicating with the backend service. The API returns the version of mysql running which is displayed to the screen.

The environment variable mapping that we added was an Environment Specific Environment Variable configuration that ONLY applies to this single instantiated ephemeral environment. In order to apply this environment variable mapping to ALL environments created moving forward, we need to move the mapping into the Default Environment Variable Configuration.

To do this, click Settings under the application in the sidebar.

This brings up the application's default settings where we need to add the mapping for all future environments that will be created from this base application configuration.

Application Settings

Click Edit to set the default environment variables for all environments and add the environment variable mapping as we did previously on the single instantiated environment.

Add lines 2 and 3 as we did previously and click SAVE AS NEW VERSION. You should see the new app version roll to 2.

All new environments created on Release will now automatically receive this new version 2 mapping scheme. We can test this by creating a new ephemeral environment.

In the sidebar, click Environments.

You can now see the previously instantiated environment. But let's create a new environment that will automatically inherit our environment variable mapping.

Click CREATE NEW ENVIRONMENT

In this dialog, select the "main" branch and "Ephemeral" as the Environment type.

Click CREATE ENVIRONMENT.

This will create and deploy a new ephemeral environment tracking the main branch.

Once the environment has been deployed, let's view the environment and see if our environment variable mapping has been applied.

Click on the Environment name from the Deploy screen. Then once inside the Environment details page, click back on the Settings tab again and you can see the new version number of 2.1. This new environment was generated using the new global Application configuration.

To verify that the default environment variable mapping was applied to the Environment, click EDIT in the Environment Variables setting where you will see the mapping in the code editor. Back on the Environment details screen, you can now click into the new frontend service hostname URL to see everything rendered as it should, with the "Hello from MySQL" message appearing.

If you quickly navigate back to the environments screen, you'll see both of your environments.

Conclusion

In this example we've built an app that contains two Docker services and a static frontend Javascript service in React. We've shown how to use Environment Specific configurations, update the Default Environment Configuration and created multiple environments. From here you can play around with doing Pull Requests on your forked repo and you'll see environments created automatically and you'll start to see the power of Release in motion!