翻译:疯狂的技术宅
作者:Matt Raible
来源:scotch
正文共:8941 字
预计阅读时间:15 分钟
假如你已经构建了一个 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 应用(https://developer.okta.com/blog/2020/03/16/react-styled-components) 一文中了解其创建方式。
登录你的 Okta 开发者帐户(你已经创建了一个(https://developer.okta.com/signup/),对吗?)注册此应用并启用 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 帐户(https://signup.heroku.com/login)。然后,安装 Heroku CLI (https://devcenter.heroku.com/articles/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 (https://github.com/heroku/heroku-buildpack-static)。
把你的更改提交到 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 (https://devcenter.heroku.com/articles/container-registry-and-runtime)直接部署你的应用。
首先,登录到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 (https://buildpacks.io/) 是 Pivotal 和 Heroku 在 2018 年初发起的一项举措。它具有 pack
CLI (https://github.com/buildpacks/pack),可让你用 buildpacks 构建 Docker 映像。
我的好朋友 Joe Kutner是 Heroku 的一名软件架构师,在实现 Cloud Native Buildpacks 中发挥了重要的作用。Joe 是 JHipster 项目的积极提交者,其作者 The Healthy Programmer 是 Cloud Native Buildpacks 核心团队的创始成员 。他对 Docker 的建议是:“如果不需要,请不要使用 Dockerfile
”。
Joe 对我在弄清楚如何使用 buildpacks 创建 Docker 映像的技术上提供了很大的帮助,所以下面的说明应该归功于他。
首先,请 install pack
(https://buildpacks.io/docs/install-pack/)。如果你使用的是 Mac 或 Linux,可以使用 Homebrew。如果用的是 Windows,可以[安装其可执行文件 (https://github.com/buildpacks/pack/releases/download/v0.10.0/pack-v0.10.0-windows.zip)。
brew tap buildpack/tap
brew install pack
在前面的 buildpacks 示例中,我用了 Heroku 的 Node.js 和静态 buildpacks。
Heroku 静态构建包不是 “Cloud Native” 构建包。它使用旧的(原生云)API。这意味着它与开箱即用的 pack
不兼容。
幸运的是,Heroku 确实提供了 cnb-shim (https://github.com/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 帐户,那就先创建一个 (https://hub.docker.com/signup)。
拥有帐户之后,登录并 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 (https://github.com/oktadeveloper/okta-react-docker-example) 上找到本示例的源代码。
原文链接
https://scotch.io/tutorials/react-docker-with-security-in-10-minutes