-
Notifications
You must be signed in to change notification settings - Fork 8
Update Ansible configuration for deploying dashboard using runtime environment variables #110
Update Ansible configuration for deploying dashboard using runtime environment variables #110
Conversation
c87c63c
to
17b302c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But how does the user verify that the yarn build
will work with that server?
The role for
|
But how does one ensure they configuration built into the UMI.js will work with the target server? In other words, the configuration used to build UMI.js file has to work with the target it will be deployed to. In the past, we did this by having the UMI.js file be independent of the host deployed to, and having a How do we ensure the same with this mechanism? |
Previously, one would have to confirm The main difference between an independent config vs. integrated config is the independent config allows you to edit the configuration after a deploy to a remote host. We are required to build a new dashboard binary for every deployment to a unique target host under the integrated config approach. The main motivation behind the integrated config approach is to reduce overhead on page components that previously queried the config file on every component mount and allow reference of config endpoints as environment variables at any point after the node process execution. This allows us to initialize bug reporting such as Sentry at the earliest point during the node process execution and optimize the breadth of information collected. Overall, we sacrifice the ability to edit the endpoint config post deployment in order to optimize for faster component performance and earlier tools initialization. |
ansible/README.md
Outdated
- An inventory file containing the server values defined | ||
|
||
## Endpoint Configuration | ||
API endpoints are configured and bundled into the final binary when running `yarn build`. Before deployment of the binary to a remote host, consider the current configuration definition at `config/endpoints.js`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, since I was playing with this yesterday afternoon trying to deploy a dashboard to my VM. I'd forgotten you'd merged the process.env
change and initially built and deployed "the old way", which didn't work.
Then when I remembered and edited endpoints.js
I found that yarn build
didn't include the changes ... I had to delete the dist/
directory contents and rebuild from scratch. Maybe worth a note that apparently just changing endpoints.js
and yarn build
isn't enough to pick up the changes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Running yarn build
should overwrite the contents in dist/
according to the UmiJS docs (yarn build
maps to umi build
in package.json
). I was able to deploy the latest dashboard changes to staging without having to delete the dist/
directory. Perhaps clearing the yarn cache might help here? https://classic.yarnpkg.com/en/docs/cli/cache/
17b302c
to
2bb2418
Compare
@portante @dbutenhof I've updated the PR to meet both requirements of referencing the dashboard endpoint config as a standalone component and referencing the dashboard endpoint config through environment variables in the bundled JavaScript code. This is accomplished by initializing a |
df50429
to
595e8bf
Compare
I like that better than embedding the parameters in the UMI build; it's much more portable. The idea that Pete and I had kicked around, which is really the basis for my #2024, is to move towards a zero-(pre) configuration, ensuring the dashboard is automatically consistent with the settings of the server it's using by having the server tell it through this new API. The only parameter that would need to be statically configured in your |
package.json
Outdated
@@ -36,6 +36,7 @@ | |||
"ant-design-pro": "^2.1.1", | |||
"antd": "^3.16.1", | |||
"classnames": "^2.2.5", | |||
"dotenv": "^8.2.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does the dotenv
package do? If I look at the Network tab of a browser console, will I see GET operations fetching the .env
file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dotenv
reads the contents of the .env
file when the Node.js process boots up. It creates an env
object as a property of the global process
object. This workflow doesn't involve network requests and is the reason we can reference configuration at the earliest point in dashboard initialization.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But is the .env
file built into the index.html page that is loaded? Or the <script ...>
references in the index.html
back on the server? How does Node.js running in the browser get the contents of the .env
? Or are you talking about a Node.js process on the server that reads this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The bundled dashboard code is configured to read the .env
file at the root of the deployed dashboard directory. This is done by adding require('dotenv').config();
to the UmiJS config which is then bundled into the umi.js
file referenced in index.html
. We don't require a Node.js process to run on a target server in order to serve the .env
file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The bundled dashboard code is configured to read the
.env
file at the root of the deployed dashboard directory. This is done by addingrequire('dotenv').config();
to the UmiJS config which is then bundled into theumi.js
file referenced inindex.html
. We don't require a Node.js process to run on a target server in order to serve the.env
file.
So then the umi.js
file is built with the contents of the .env
file, and then the umi.js
file is deployed to the target server?
Do we all agree that the principle of creating a deployable umi.js
file once and deploying it to multiple environments is one we want to adhere to as a project?
If we all agree, great.
If we don't agree with that principle, we need to discuss that first because we need a guide for how we handle builds and deployment.
That principle is at the heart of containers (build the container once, deploy it via different orchestrators [podman, kubernetes, others]), of Ansible (roles and playbooks are applied to various inventory files with different contents), and CI/CD pipelines (build once, test the same object without changes through the pipeline until deployed).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The bundled dashboard code is configured to read the
.env
file at the root of the deployed dashboard directory. This is done by addingrequire('dotenv').config();
to the UmiJS config which is then bundled into theumi.js
file referenced inindex.html
. We don't require a Node.js process to run on a target server in order to serve the.env
file.So then the
umi.js
file is built with the contents of the.env
file, and then theumi.js
file is deployed to the target server?
Hmm; good question, but there is a /var/www/html/dashboard/.env
on the staging server, and my impression was that dotenv
is somehow sucking that in. I don't really see how that could happen with a browser and the static dashboard Javascript on the server unless it's doing an HTML GET to retrieve it just like it does the CSS.
Do we all agree that the principle of creating a deployable
umi.js
file once and deploying it to multiple environments is one we want to adhere to as a project?
Yes, very strongly!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with the "build once, deploy anywhere" paradigm. The aim of this PR is to bridge the gap between deploying to multiple environments with one binary while also allowing endpoint config to be referenced at dashboard initialization. The discussion in this issue captures why this is an uncommon pattern in React environments and generally requires a "hacked" workaround: facebook/create-react-app#2353
I've reviewed suggested workarounds and come up with a solution to configure endpoints at dashboard runtime so we avoid bundling endpoints into the dashboard binary. We do this by referencing <script src="<%= context.config.publicPath +'endpoints.js'%>"></script>
in the dashboard index.html
template and fetching endpoints.js
with a GET
request. endpoints.js
is included in dist/
as a standalone file and can be modified after deployment.
I've deployed the dashboard to staging using this model. Feel free to inspect the Network tab in dev tools to see the endpoints.js
file being queried. Additionally, you can modify endpoints.js
and refresh the dashboard to try different API endpoints.
ansible/README.md
Outdated
prefix='test_prefix.' | ||
result_index='test_index.' | ||
run_index='test_index.' | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
}
?? I don't see an opening brace, so I assume this was an accident?
package.json
Outdated
@@ -36,6 +36,7 @@ | |||
"ant-design-pro": "^2.1.1", | |||
"antd": "^3.16.1", | |||
"classnames": "^2.2.5", | |||
"dotenv": "^8.2.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The bundled dashboard code is configured to read the
.env
file at the root of the deployed dashboard directory. This is done by addingrequire('dotenv').config();
to the UmiJS config which is then bundled into theumi.js
file referenced inindex.html
. We don't require a Node.js process to run on a target server in order to serve the.env
file.So then the
umi.js
file is built with the contents of the.env
file, and then theumi.js
file is deployed to the target server?
Hmm; good question, but there is a /var/www/html/dashboard/.env
on the staging server, and my impression was that dotenv
is somehow sucking that in. I don't really see how that could happen with a browser and the static dashboard Javascript on the server unless it's doing an HTML GET to retrieve it just like it does the CSS.
Do we all agree that the principle of creating a deployable
umi.js
file once and deploying it to multiple environments is one we want to adhere to as a project?
Yes, very strongly!
595e8bf
to
7f27c6b
Compare
7f27c6b
to
ecec0fb
Compare
environment variables
ecec0fb
to
a3599e4
Compare
<link rel="icon" href="<%= context.config.publicPath +'favicon.ico'%>" type="image/x-icon"> | ||
|
||
<!-- runtime endpoints config --> | ||
<script src="<%= context.config.publicPath +'endpoints.js'%>"></script> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't seen that <%=
syntax before. What does that actually mean? I tried looking it up, but what I found wasn't really helpful. Is it just a Javascript environment to allow the path concatenation operator?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has been adapted from a framework called ejs. It allows for dynamic HTML templating and has some pretty cool features!
The initialization of a
config.json.j2
file is no longer required as the dashboard bundles the endpoint configuration file (config/endpoints.js
) into the final binary deployed to a remote host. In order to reflect this change, theinventory
file has been simplified to only reference hosts being deployed to under the[servers]
key.The process for deploying the dashboard to a remote host using Ansible remains the same by running the following: