作者:Matt Raible翻译:疯狂的技术宅
原文:https://scotch.io/tutorials/r...
未经允许严禁转载
假如你已经构建了一个 React 应用,但是现在需要部署它。应该怎么做?首先,最好选择一个云提供商,因为它们一般成本低而且部署容易。
大多数云提供商都提供了一种部署静态站点的方法。用 React 构建应用只是 JavaScript、HTML 和 CSS。它们是静态文件,几乎可以在任何 Web 服务器上使用。但实际上,如果你使用了 JSX(JS 中的 HTML)和样式化组件,那么这些可以说只有 JavaScript!
Docker 是用于构建和共享容器化应用的事实标准。你可以使用它打包你的应用程序,并包含多种开源 Web 服务器来为你的应用程序提供服务。另外,你还可以通过配置网络服务器来发送安全标头,这样使你的程序更安全。
前提条件:
为了集中精力,我用了一位同事已经构建的程序。首先克隆存储库。
git clone https://github.com/oktadeveloper/okta-react-styled-components-example.git react-docker cd react-docker npm install
这是一个使用样式化组件的 React 应用,并由 OpenID Connect(aka OIDC)保护。你可以在使用样式化组件构建 React 应用 一文中了解其创建方式。
登录你的 Okta 开发者帐户(你已经创建了一个,对吗?)注册此应用并启用 OIDC 身份验证。
React Docker
。3000
,并且 Login redirect URI 为 http://localhost:3000/callback
出现的界面将为你提供一个客户端 ID。
将客户端 ID 复制并粘贴到应用程序的 src/App.js
中。 <yourIssuerURI>
的值可以在 Okta 仪表板的 API > Authorization Servers 下找到。例如我的是 https://dev-133320.okta.com/oauth2/default
。
function App() { return ( <Router> <Security issuer='<yourIssuerURI>' clientId='<yourClientId>' redirectUri={window.location.origin + '/callback'} pkce={true}> <SecureRoute path='/' exact={true} component={Calendar}/> <Route path='/callback' component={LoginCallback}/> </Security> </Router> ); }
<>
括号只是占位符,请确保将其删除!
用 npm start
启动你的应用。你将被重定向到 Okta 进行身份验证,然后返你的应用。如果你没有重定向,那是因为你已经登录。请在 private 窗口中重试来查看登录过程。
你会看到一个简单、干净的日历,并选择了今天的日期。
我承认这是一个非常简单的应用,但我们会用它来演示如何用 Docker 进行容器化。
你可能会问:“为什么要用 Docker?这不会使事情复杂化吗?”
是的我同意。用 Docker 进行操作比用 Heroku 进行 firebase deploy
或 git push
处理更为复杂。但是如果你真的要使事情复杂化,并用 Kubernetes 去管理你的应用,那么它可以给你更多的控制权。 😛
在你的根目录中创建一个 Dockerfile
。
FROM node:14.1-alpine AS builder WORKDIR /opt/web COPY package.json package-lock.json ./ RUN npm install ENV PATH="./node_modules/.bin:$PATH" COPY . ./ RUN npm run build FROM nginx:1.17-alpine RUN apk --no-cache add curl RUN curl -L https://github.com/a8m/envsubst/releases/download/v1.1.0/envsubst-`uname -s`-`uname -m` -o envsubst && \ chmod +x envsubst && \ mv envsubst /usr/local/bin COPY ./nginx.config /etc/nginx/nginx.template CMD ["/bin/sh", "-c", "envsubst < /etc/nginx/nginx.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"] COPY --from=builder /opt/web/build /usr/share/nginx/html
这将会构建你的项目并把 Nginx 添加为 Web服务器。它还将安装 envsubst
版本,该版本允许你用环境变量去替换变量,并设置默认值。
在同一目录中创建一个 nginx.config
:
server { listen ${PORT:-80}; server_name _; root /usr/share/nginx/html; index index.html; location / { try_files $$uri /index.html; } }
这个文件把 Nginx 配置为将你的 React 应用作为 SPA(其中所有路由都转到 index.html
)并在 80 端口上运行。在 uri 前面有两个 $$
,以防止 $uri
被替换为空白值。
先执行 docker ps
确保你的 Docker 守护进程正在运行。然后运行以下命令来构建你的 Docker 镜像。 命令中的 react-docker
可以是你想要为镜像命名的任何名字。
docker build -t react-docker .
该过程完成后,你将会看到以下消息的内容:
Successfully built 3211a1255527 Successfully tagged react-docker:latest
现在,你可以用 docker run
命令通过 Docker 在端口 3000 上运行 React 应用。
docker run -p 3000:80 react-docker
如果你发现这些 docker
命令很难记住,也可以在 package.json
文件中添加几个脚本 。
"docker": "docker build -t react-docker .", "react-docker": "docker run -p 3000:80 react-docker"
然后就可以用 npm run docker
和 npm run react-docker
运行了。
很漂亮吧?在短短几分钟内就把你的 React 应用做了 docker 化。 🎉
你的应用要直到正式投入生产时才会真正的存在,所以让我们把它部署到 Heroku。首先我将向你展示怎样不用 Docker 做到这一点。
首先,你需要 一个 Heroku 帐户。然后,安装 Heroku CLI。
打开终端,登录你的 Heroku 帐户,然后创建一个新应用。
heroku login heroku create
现在,你应该有了一个新的 heroku
Git 远程存储库。可以用 git remote -v
来确认。
在带有安全标头的根目录中创建一个 static.json
文件,并把所有 HTTP 请求重定向到 HTTPS。
{ "headers": { "/**": { "Content-Security-Policy": "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self' https://*.okta.com;", "Referrer-Policy": "no-referrer, strict-origin-when-cross-origin", "Strict-Transport-Security": "max-age=63072000; includeSubDomains", "X-Content-Type-Options": "nosniff", "X-Frame-Options": "DENY", "X-XSS-Protection": "1; mode=block", "Feature-Policy": "accelerometer 'none'; camera 'none'; microphone 'none'" } }, "https_only": true, "root": "build/", "routes": { "/**": "index.html" } }
要读取 “static.json”,你必须用 Heroku static buildpack。
把你的更改提交到 Git,添加 Node.js + static buildpack,然后部署 React 应用。
git commit -am "Configure secure headers and static buildpacks" heroku buildpacks:set heroku/nodejs heroku buildpacks:add https://github.com/heroku/heroku-buildpack-static.git git push heroku master
该过程完成后,使用以下方法在浏览器中打开你的应用程序:
heroku open
你将会被重定向到 Okta,可能会看到以下错误:
The 'redirect_uri' parameter must be an absolute URI that is whitelisted in the client app settings.
要解决这个问题,需要修改 Okta 应用,以将你的 Heroku URL 添加为“登录重定向 URI”。例如https://gentle-peak-37809.herokuapp.com/callback
。
现在,你应该可以登录并看到你的应用在 Heroku 上运行了!你可以在 https://securityheaders.com 上验证其安全标头是否正确。
在这个部署示例中,buildpacks 为你完成了所有工作。但是并非每个云提供商都提供 buildpack。这就是需要 Docker 的地方。
当涉及到 Docker 镜像时,Heroku 具有一些出色的功能。如果你的项目有一个 Dockerfile,则可以用 Heroku Container Registry直接部署你的应用。
首先,登录到Container Registry。
heroku container:login
然后,创建一个新的应用。
heroku create
把 Git URL 作为新的 remote 添加到你的应用。
git remote add docker https://git.heroku.com/<your-app-name>.git
然后,把将你的 Docker 镜像 push 到 Heroku 的 Container Registry。
heroku container:push web --remote docker
该过程完成后,release 你的应用程序镜像:
heroku container:release web --remote docker
然后,在浏览器中打开该应用:
heroku open --remote docker
你需要先在 Okta 中添加应用的 URI,然后才能登录。
如果在 securityheaders.com 上的 Docker 站点中测试新的 Nginx,你的得分应该是 F。
为了解决这个问题,修改你的 nginx.config
添加安全头。
server { listen ${PORT:-80}; server_name _; root /usr/share/nginx/html; index index.html; location / { try_files $$uri /index.html; } add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self' https://*.okta.com;"; add_header Referrer-Policy "no-referrer, strict-origin-when-cross-origin"; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; add_header X-Content-Type-Options nosniff; add_header X-Frame-Options DENY; add_header X-XSS-Protection "1; mode=block"; add_header Feature-Policy "accelerometer 'none'; camera 'none'; microphone 'none'"; }
更新文件后,运行以下命令:
heroku container:push web --remote docker heroku container:release web --remote docker
现在你应该得到 A!
在本文中,我们学习了把 React 应用部署到 Heroku 的两种方法。首先是利用 buildpack 和 git push
。第二个是使用 Heroku 的 Container Registry 和 heroku container:push
+ heroku push:release
。
Cloud Native Buildpacks 是 Pivotal 和 Heroku 在 2018 年初发起的一项举措。它具有 pack
CLI,可让你用 buildpacks 构建 Docker 映像。
我的好朋友 Joe Kutner是 Heroku 的一名软件架构师,在实现 Cloud Native Buildpacks 中发挥了重要的作用。 Joe 是 JHipster 项目的积极提交者,其作者 The Healthy Programmer 是 Cloud Native Buildpacks 核心团队的创始成员 。他对 Docker 的建议是:“如果不需要,请不要使用 Dockerfile
”。
Joe 对我在弄清楚如何使用 buildpacks 创建 Docker 映像的技术上提供了很大的帮助,所以下面的说明应该归功于他。
首先,请 installpack
。如果你使用的是 Mac 或 Linux,可以使用 Homebrew。如果用的是 Windows,可以安装其可执行文件。
brew tap buildpack/tap brew install pack
在前面的 buildpacks 示例中,我用了 Heroku 的 Node.js 和静态 buildpacks。
Heroku 静态构建包不是 “Cloud Native” 构建包。它使用旧的(原生云)API。这意味着它与开箱即用的 pack
不兼容。
幸运的是,Heroku 确实提供了 cnb-shim,你可以用它来使其工作。在用 cnb-shim
转换后,Joe 为 Heroku 的静态 buildpack 创建了一个 URL (https://cnb-shim.herokuapp.com/v1/heroku-community/static
) 。
在本地构建和运行 Docker 镜像之前,必须先进行一项更改。 从 static.json 中删除 "https_only":true
这一行。
然后用以下命令通过 Node.js 和静态 buildpack(也就是你在 Heroku 上使用的相同 buildpack)构建 Docker 镜像。
pack build react-pack --builder heroku/buildpacks --buildpack \ heroku/nodejs,https://cnb-shim.herokuapp.com/v1/heroku-community/static
提示:如果你想摆脱 --builder
参数,可以用 pack set-default-builder heroku/buildpacks
。
该过程完成后,你应该可以运行它。
docker run --rm -it --init -p 3000:3000 --env PORT=3000 okta
如果你发现这些 pack
命令很难被记住,那么可以把它们添加到 package.json
中。
"pack": "pack build react-pack --builder heroku/buildpacks --buildpack heroku/nodejs,https://cnb-shim.herokuapp.com/v1/heroku-community/static", "react-pack": "docker run --rm -it --init -p 3000:3000 --env PORT=3000 react-pack"
然后可以使用 npm run pack
和 npm run react-pack
来运行它们。
通过把它们部署到 Docker Hub 等注册表中,可以轻松共享 Docker 容器。如果你还没有 Docker Hub 帐户,那就先创建一个。
拥有帐户之后,登录并 push 你的镜像。在下面的示例中,我正在使用 react-docker
,但你也可以使用 react-pack
来部署 buildpacks 版本。
docker login docker image tag react-docker <your-username>/react-docker docker push <your-username>/react-docker
默认情况下,这会将其标记为 latest
。如果要标记和推送特定版本,可以用:
docker image tag react-docker <your-username>/react-docker:1.0 docker push <your-username>/react-docker
然后其他人就可以用以下命令 pull 并运行:
docker run -p 3000:80 <your-username>/react-docker
要把现有映像部署到 Heroku,可以用 docker push
。你必须用以下命名约定来标记和推送镜像。
docker tag <image> registry.heroku.com/<app>/<process-type> docker push registry.heroku.com/<app>/<process-type>
要部署 react-pack
镜像,你可以执行以下操作:
docker tag react-pack registry.heroku.com/fierce-eyrie-08414/web docker push registry.heroku.com/fierce-eyrie-08414/web heroku container:release web --remote docker
我尝试了一下,发现没有强制使用 HTTPS。必须将 "https_only":true
添加到 static.json
中,然后重新push。
在本教程中,我们学习了如何用 Docker 容器化你的 React 应用。你可以用 docker build
手动进行这项操作,也可以用 Heroku 的 Container Registry 通过 Dockerfile 推送和发布项目。在构建容器时,还可以用 pack
命令来利用 Cloud-Native + Heroku 构建包。
如果你用的是 Heroku,它的 buildpack 比 Docker 更容易使用。通过简单的 git push
,你可以在 Heroku 的服务器上部署代码并构建。
可以在 GitHub上 的 oktadeveloper/okta-react-docker-example 上找到本示例的源代码。