要云还是不云?
要决定要做什么,第一步是问自己是否主持:
- 内部部署
- 在云端
- 甚至使用我自己的机器
首先,让我们从选项中删除内部部署。 这是没有道理的,因为我是唯一的用户。 相反,选择云有两个原因:
- 该应用程序需要对事件做出反应:事件是在Trello板上移动卡。 因此,它需要一直处于运行状态,并且需要保持运行状态。 使用云提供商可以做到这一点。 另一种方法是每次在我的机器上启动应用程序,与Trello交互,然后再次停止应用程序。
- 该应用需要可从Trello访问。 我已经写了如何配置
ngrok
以在其机器上从Web接收HTTP请求的方法。 尽管可以用于调试目的,但对于生产目的来说并不是一个好主意。
选择哪个云平台?
既然托管在云中的选项已经解决,现在是时候选择自己的PaaS提供商了。 有几种选择:
- Google Cloud Platform
- 微软Azure
- 亚马逊网络服务
- IBM云
- 甲骨文云
- 还有其他几个
此外,还需要构建工具管道:我需要全面的CI作业。 从实施的持续部署中受益也将是一个不错的选择。 这个想法是在每次提交时自动构建和部署应用程序。 但是,我的主要要求是易于使用:我想避免设置堆栈,而这需要一个专职的软件可靠性工程师和24/7监控。 我对大型提供商的堆栈的理解是,它们非常复杂。
Heroku营救
幸运的是,除此之外,我还知道一个合适的提供商: Heroku 。
Heroku是基于托管容器系统的平台即服务,具有集成的数据服务和强大的生态系统,用于部署和运行现代应用程序。 Heroku开发人员的经验是一种以应用程序为中心的软件交付方法,并与当今最受欢迎的开发人员工具和工作流集成在一起。
在Heroku内部,基本的构建基块称为dyno 。 Heroku建立在容器化之上:dyno是一个隔离的容器化过程,专用于执行具有特定RAM量的代码。 根据负载,可以添加/删除测功机以在水平方向上缩放。 一些更高的定价计划允许根据负载自动进行缩放。 作为唯一的用户,一个测力计就足以满足我的需求。
在这种情况下,免费计划就可以满足要求。 以下是其一些功能:
- 闲置30分钟后切换到睡眠模式
- 每月1,000小时的活动
- 自定义子域
我有两个主要用途的应用程序:
- 当我提交会议时,我会“爆发”。 我在日历中占用了半天的时间段,并在此期间参加了多个会议。 每次提交之后,我都将Trello卡从“ 待办事项”列移至“已提交”列,如本系列第一篇文章所述 。
- 收到会议更新时,只需将卡从“已提交”列移至相关的“已接受”或“已拒绝” 。
在这两种情况下,我都可以应对睡眠问题,因为既不需要在特定的时间范围内更新日历,也不需要更新工作表。
但是,Heroku的最大优势是恕我直言,它的嵌入式持续部署模型与其专用的Git存储库相关联。 这样一来,每次推送到master
分支就可以触发生成程序包的构建,并将其部署到生产环境中。 让我们看看如何完成它。
Heroku的5分钟速成班
Heroku带有Web界面以及专用的命令行界面。 我建议安装CLI :
brew tap heroku/brew&& brew install heroku
现在可以对自己的帐户进行身份验证:
heroku login
从那时起,让我们创建一个应用程序。
heroku create dummy
该应用程序绑定到一个子域。 可从< https://dummy.herokuapp.com>访问该dummy
应用程序; 另外,底层的Git存储库托管在https://git.heroku.com/dummy.git上 。 通过从应用程序的根文件夹运行先前的命令,应该将新创建的远程Git存储库添加为heroku
远程。 现在,每次向master
推送都应构建工件并进行部署 :
git push heroku master
Heroku通过推断技术堆栈和构建工具来做到这一点。 例如,它识别位于应用程序根目录的Maven POM。 上一个推送显示如下:
remote: Compressing source files... done. remote: Building source: remote: remote: -----> Java app detected remote: -----> Installing JDK 1.8... done remote: -----> Executing Maven remote: $ ./mvnw -DskipTests clean dependency:list install remote: [INFO] Scanning for projects... remote: [INFO] remote: [INFO] ----------------< ch.frankel.conftools:conf-automation >---------------- remote: [INFO] Building conf-automation 0.0.1-SNAPSHOT remote: [INFO] --------------------------------[ jar ]--------------------------------- remote: [INFO] remote: [INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ conf-automation --- remote: [INFO] remote: [INFO] --- maven-dependency-plugin:3.1.1:list (default-cli) @ conf-automation --- remote: [INFO] remote: [INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ conf-automation --- remote: [INFO] Using 'UTF-8' encoding to copy filtered resources. remote: [INFO] Copying 2 resources remote: [INFO] Copying 2 resources remote: [INFO] remote: [INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ conf-automation --- remote: [INFO] Nothing to compile - all classes are up to date remote: [INFO] remote: [INFO] --- kotlin-maven-plugin:1.3.50:compile (compile) @ conf-automation --- remote: [INFO] Applied plugin: 'spring' remote: [WARNING] /tmp/build_bc06910fc8b3d2c530bcec797ce67d25/src/main/kotlin/ch/frankel/conf/automation/TriggerHandler.kt: (25, 14) Parameter 'request' is never used remote: [WARNING] /tmp/build_bc06910fc8b3d2c530bcec797ce67d25/src/main/kotlin/ch/frankel/conf/automation/action/AddSheetRow.kt: (51, 31) Unchecked cast: Any! to Collection<Any> remote: [INFO] remote: [INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ conf-automation --- remote: [INFO] Using 'UTF-8' encoding to copy filtered resources. remote: [INFO] skip non existing resourceDirectory /tmp/build_bc06910fc8b3d2c530bcec797ce67d25/src/test/resources remote: [INFO] remote: [INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ conf-automation --- remote: [INFO] Changes detected - recompiling the module! remote: [INFO] remote: [INFO] --- kotlin-maven-plugin:1.3.50:test-compile (test-compile) @ conf-automation --- remote: [INFO] Applied plugin: 'spring' remote: [INFO] remote: [INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ conf-automation --- remote: [INFO] Tests are skipped. remote: [INFO] remote: [INFO] --- maven-jar-plugin:3.1.2:jar (default-jar) @ conf-automation --- remote: [INFO] Building jar: /tmp/build_bc06910fc8b3d2c530bcec797ce67d25/target/conf-automation-0.0.1-SNAPSHOT.jar remote: [INFO] remote: [INFO] --- spring-boot-maven-plugin:2.2.0.RELEASE:repackage (repackage) @ conf-automation --- remote: [INFO] Replacing main artifact with repackaged archive remote: [INFO] remote: [INFO] --- maven-install-plugin:2.5.2:install (default-install) @ conf-automation --- remote: [INFO] Installing /tmp/build_bc06910fc8b3d2c530bcec797ce67d25/target/conf-automation-0.0.1-SNAPSHOT.jar to /app/tmp/cache/.m2/repository/ch/frankel/conftools/conf-automation/0.0.1-SNAPSHOT/conf-automation-0.0.1-SNAPSHOT.jar remote: [INFO] Installing /tmp/build_bc06910fc8b3d2c530bcec797ce67d25/pom.xml to /app/tmp/cache/.m2/repository/ch/frankel/conftools/conf-automation/0.0.1-SNAPSHOT/conf-automation-0.0.1-SNAPSHOT.pom remote: [INFO] ------------------------------------------------------------------------ remote: [INFO] BUILD SUCCESS remote: [INFO] ------------------------------------------------------------------------ remote: [INFO] Total time: 21.087 s remote: [INFO] Finished at: 2020-04-13T08:17:18Z remote: [INFO] ------------------------------------------------------------------------ remote: -----> Discovering process types remote: Procfile declares types -> web remote: remote: -----> Compressing... remote: Done: 86.1M remote: -----> Launching... remote: Released v41 remote: https://dummy.herokuapp.com/ deployed to Heroku remote: remote: Verifying deploy... done.
可以通过位于Procfile
根目录的专用Procfile
配置部署参数。 一种替代方法是使用heroku.yml
文件。 就我而言,这是Procfile
:
web: java $JAVA_OPTS -jar target/conf-automation-0.0.1-SNAPSHOT.jar --spring.profiles.active=production --server.port=$PORT
-
web
将应用配置为可通过HTTP访问 - 另一部分是启动应用程序的实际命令行。 如果您已经通过CLI启动了Spring Boot应用程序,那将是非常容易识别的
- 唯一的难题是
--server.port=$PORT
参数。 Heroku决定应用程序应绑定到哪个端口,并将其导出到$PORT
环境变量中。 这个参数使Spring Boot接收到HTTP请求。
部署将停止正在运行的JVM,部署新的JAR,然后使用此新的JAR重新启动JVM。 如果使用一个单独的dyno,则预计停机时间是指JVM启动所需的时间。
最后,该应用程序需要一个数据库。 默认情况下,Spring Boot使用H2内存数据库。 这意味着,当应用出现故障例如 ,由于睡眠的,所有数据都会丢失。 Camunda秘密使用该数据库存储所有与工作流程相关的数据。 因此,我将Spring Boot配置为使用PostgreSQL来访问持久化的数据,以防出现问题。
Heroku允许为应用程序设置称为附加组件的附加服务。 附加组件有多种类型,例如数据存储,日志记录,监视,搜索等。 一个附加组件包装了PostgreSQL并将其提供给应用程序。
免费计划将存储限制为10,000行。 因此,当我收到有关接近极限的电子邮件警告时,我需要定期手动重置存储的数据。 我现在要回到H2,因为我不需要调试:一切都按预期进行。
结论
在本系列中,我描述了如何自动完成围绕会议提交的无聊的管理任务。 首先,我展示了上下文和需求,以及本地测试的方法。 然后,我继续详细介绍了将应用程序与Google日历和Google表格集成的必要步骤。 最后,我描述了如何在Heroku上部署应用程序。
一旦成为开发人员,就永远是开发人员。 当您学习了如何编程时,重复的手工工作就变成了一个编码难题。
翻译自: https://blog.frankel.ch/automating-conference-submission-workflow/3/