estado: construção contínua
Este texto está mais para uma coleção de resultados, não é propriamente um relatório.
recomendo a leitura da descrição na wikipedia pois traz uma idéia do que é e de alguns conceitos usados na ferramenta.
Heroku é um serviço que oferece uma plataforma na nuvem para implantar outros serviços na nuvem. Desenvolvimento e testes podem ser feitos localmente, inclusive da interface no navegador.
Para poder implantar no Heroku, é necessário construir o serviço de acordo com o que é oferecido pela plataforma.
Heroku não oferece uma máquina virtual, como fazem Linode e EC2, e não oferece um sistema de arquivos para escrita. Ele oferece slugs, que são containers para os dados (por exemplo páginas estáticas e imagem do executável do serviço do usuário), dynos, que são máquinas de execução, e, armazenamento em um banco de dados POSTGRES.
A visão geral do funcionamento de Heroku e do vocabulário usado na documentação, em especial de conceitos particulares a Heroku, é esclarecido aqui.
A documentação do Heroku é acessada pelo devcenter.
A fim de facilitar a criação (local) do código, padronizar sua estrutura e compilação, Heroku usa maven.
A fim de implantar o sistema do usuário na nuvem, Heroku usa git (pode usar outros).
Há (pelo menos) duas interfaces de configuração: O dashboard, acessado com navegador pelo site heroku.com imagem, e a interface de linha de comando (ou CLI) imagem da instalação no Ubuntu 20.04LTS, um programa executado localmente com o comando heroku
.
Instruções para instalar e usar o cliente
Instruções para implantar usando git
O usuário pode escrever seu serviço em várias linguagens de programação. Acredito que, para o meu propósito, Java é a melhor linguagem.
Instruções para implantar código em Java
Seguirei alguns exemplos, documentando como resultado.
Explica o que é dyno, slug, Procfiles, Buildpacks, release.
- Dynos are isolated, virtualized Unix containers, that provide the environment required to run an application.
- Procfiles list process types - named commands that you may want executed.
- Deploying applications involves sending the application to Heroku using either Git, GitHub, or via an API.
- Buildpacks lie behind the slug compilation process. Buildpacks take your application, its dependencies, and the language runtime, and produce slugs.
- A slug is a bundle of your source, fetched dependencies, the language runtime, and compiled/generated output of the build system - ready for execution.
- Config vars contain customizable configuration data that can be changed independently of your source code. The configuration is exposed to a running application via environment variables.
- Add-ons are third party, specialized, value-added cloud services that can be easily attached to an application, extending its functionality.
- A release is a combination of a slug (your application), config vars and add-ons. Heroku maintains an append-only ledger of releases you make.
Executar Fuseki, ou algo equivalente, na plataforma Heroku.
À medida que eu for construindo jeitos de trabalhar (significados), na minha opinião, explicáveis e úteis na direção de atingir o objetivo, acrescento aqui como texto ou como link, na seção Resultados.
Como este relatório vai sendo escrito durante o processo (exploratório) até chegar ao objetivo, muitos resultados são accomplishments e não achievements (conforme definidos em PlansLite). Ié são qualificados como feitos ou conquistas mas não precisam ser consequências das tarefas que levam ao objetivo. Consequentemente, alguns resultados apresentados aqui não fazem parte de uma sequência de atividades para atingir o objetivo principal. No momento não se sabe que atividades, nem em que sequência, permitem atingir o objetivo principal.
A ordem de apresentação dos resultados no texto não precisa refletir a ordem cronológica em que esses resultados foram sendo obtidos.
O tutorial recomenda baixar um exemplo pronto, clonando do github. As instruções do readme do repositório são bem mais sintéticas que as do artigo de Heroku. Em quatro linhas executa localmente, em três implanta e executa no Heroku.
Este exemplo usa Spring, então fui ver como funciona. Em princípio, algumas anotações no código Java servem para indicar que método deve ser usado em resposta a que requisição. O valor de retorno do método é o nome do arquivo.
https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/SpringApplication.html https://spring.io/ https://spring.io/quickstart https://www.baeldung.com/spring-requestmapping https://springframework.guru/spring-requestmapping-annotation/ https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/GetMapping.html
A organização dos arquivos é baseada em um MVC.
https://pt.wikipedia.org/wiki/MVC https://www.logicbig.com/tutorials/spring-framework/spring-web-mvc/spring-mvc-intro.html https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/mvc.html
Então, incluindo no código de Main.java as linhas:
// https://spring.io/
// @GetMapping("/helloworld")
@RequestMapping("/helloworld")
public String hello() {
// return "Hello World!";
return "hello";
}
e incluindo em java-getting-started/src/main/resources/templates$
um arquivo hello.html
imagem, e executando mvn install
imagem para compilar e heroku local:start
, devo conseguir acessar localhost:5000/helloworld
notas: Nesta configuração, @RequestMapping
informa qual o nome da página imagem. @GetMapping
dá erro de compilação imagem.
Com isto já dá para pensar em ter um subconjunto de Fuseki sendo executado sobre uma base de conhecimento carregada dos templates, que recebe novas triplas e as armazena em memória.
Outra alternativa seria usar JDBC e o POSTGRES do Heroku.
Heroku é muito aderente a Maven, então segue alguma informação:
Maven Phases
Although hardly a comprehensive list, these are the most common default lifecycle phases executed.
- validate: validate the project is correct and all necessary information is available
- compile: compile the source code of the project
- test: test the compiled source code using a suitable unit testing framework. These tests should not require the code be packaged or deployed
- package: take the compiled code and package it in its distributable format, such as a JAR.
- integration-test: process and deploy the package if necessary into an environment where integration tests can be run
- verify: run any checks to verify the package is valid and meets quality criteria
- install: install the package into the local repository, for use as a dependency in other projects locally
- deploy: done in an integration or release environment, copies the final package to the remote repository for sharing with other developers and projects.
There are two other Maven lifecycles of note beyond the default list above. They are
- clean: cleans up artifacts created by prior builds
- site: generates site documentation for this project
Referência aqui
Acho que diferentes tutoriais são escritos por pessoas usando comandos ligeiramente diferentes. É bom para mostrar que há várias formas de fazer algo, mas é ruim porque não é uniforme. Por exemplo, neste tutorial, abre-se mostrando como devia ser o comando para executar e a execução:
$ java -jar webapp-runner.jar application.war
deploying app from: /Users/johnsimone/dev/gitrepos/devcenter-webapp-runner/target/webappRunnerSample.war
Feb 14, 2012 5:21:44 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-bio-8080"]
Feb 14, 2012 5:21:44 PM org.apache.catalina.core.StandardService startInternal
INFO: Starting service Tomcat
Feb 14, 2012 5:21:44 PM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/8.0.30
Feb 14, 2012 5:21:44 PM org.apache.catalina.startup.ContextConfig webConfig
INFO: No global web.xml found
Feb 14, 2012 5:21:44 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-bio-8080"]
Aí, depois de criar o esboço, ajustar o POM, e empacotar, o comando para executar é: java -jar target/dependency/webapp-runner.jar target/*.war
, que é a certa.
Enfim, segui os seguintes passos:
fabio@fabio-13Z940-G-BK71P1:~/Documentos/heroku/deploy-war/hello2$ mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp WARNING: An illegal reflective access operation has occurred WARNING: Illegal reflective access by com.google.inject.internal.cglib.core.$ReflectUtils$1 (file:/usr/share/maven/lib/guice.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) WARNING: Please consider reporting this to the maintainers of com.google.inject.internal.cglib.core.$ReflectUtils$1 WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations WARNING: All illegal access operations will be denied in a future release [INFO] Scanning for projects... [INFO] [INFO] ------------------< org.apache.maven:standalone-pom >------------------- [INFO] Building Maven Stub Project (No POM) 1 [INFO] --------------------------------[ pom ]--------------------------------- [INFO] [INFO] >>> maven-archetype-plugin:3.2.0:generate (default-cli) > generate-sources @ standalone-pom >>> [INFO] [INFO] <<< maven-archetype-plugin:3.2.0:generate (default-cli) < generate-sources @ standalone-pom <<< [INFO] [INFO] [INFO] --- maven-archetype-plugin:3.2.0:generate (default-cli) @ standalone-pom --- [INFO] Generating project in Interactive mode Define value for property 'groupId': com.example Define value for property 'artifactId': helloworld Define value for property 'version' 1.0-SNAPSHOT: : Define value for property 'package' com.example: : Confirm properties configuration: groupId: com.example artifactId: helloworld version: 1.0-SNAPSHOT package: com.example Y: : [INFO] ---------------------------------------------------------------------------- [INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-webapp:1.0 [INFO] ---------------------------------------------------------------------------- [INFO] Parameter: basedir, Value: /home/fabio/Documentos/heroku/deploy-war/hello2 [INFO] Parameter: package, Value: com.example [INFO] Parameter: groupId, Value: com.example [INFO] Parameter: artifactId, Value: helloworld [INFO] Parameter: packageName, Value: com.example [INFO] Parameter: version, Value: 1.0-SNAPSHOT [INFO] project created from Old (1.x) Archetype in dir: /home/fabio/Documentos/heroku/deploy-war/hello2/helloworld [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 01:06 min [INFO] Finished at: 2021-01-26T18:48:22-03:00 [INFO] ------------------------------------------------------------------------ fabio@fabio-13Z940-G-BK71P1:~/Documentos/heroku/deploy-war/hello2$
- No tutorial não está escrito que uma subpasta com o nome que informamos como artifactId é criada;
- O esboço é completo.
mvn package
cria ohelloworld.war
que não sei se contém ou se aponta paratarget/helloworld/index.jsp
.
Fiz uns testes:
- colocar
sample.war
, baixado dos exemplos de Tomcat na pasta target e tentar executar localmente.- resulta que
java -jar target/dependency/webapp-runner.jar target/*.war
avisa que não executa os dois.war
simultaneamente e usa um deles.
- resulta que
fabio@fabio-13Z940-G-BK71P1:~/Documentos/heroku/deploy-war/helloworld$ java -jar target/dependency/webapp-runner.jar target/*.war WARNING: multiple paths are specified, but no longer supported. First path will be used.
- tirar o
helloworld.war
, colocarfuseki.war
e (tentar) executar.
fabio@fabio-13Z940-G-BK71P1:~/Documentos/heroku/deploy-war/helloworld/target$ ls classes helloworld maven-archiver tomcat.8080 dependency helloworld.war.hide sample.war fabio@fabio-13Z940-G-BK71P1:~/Documentos/heroku/deploy-war/helloworld/target$ mv sample.war sample.war.hide fabio@fabio-13Z940-G-BK71P1:~/Documentos/heroku/deploy-war/helloworld/target$ cp ~/apache-jena-fuseki-3.17.0/fuseki.war . fabio@fabio-13Z940-G-BK71P1:~/Documentos/heroku/deploy-war/helloworld/target$ ls classes fuseki.war helloworld.war.hide sample.war.hide dependency helloworld maven-archiver tomcat.8080 fabio@fabio-13Z940-G-BK71P1:~/Documentos/heroku/deploy-war/helloworld/target$ cd .. fabio@fabio-13Z940-G-BK71P1:~/Documentos/heroku/deploy-war/helloworld$ java -jar target/dependency/webapp-runner.jar target/*.war jan 25, 2021 5:17:35 PM org.apache.catalina.startup.ExpandWar expand INFORMAÇÕES: An expanded directory [/home/fabio/Documentos/heroku/deploy-war/helloworld/target/tomcat.8080/webapps/expanded] was found with a last modified time that did not match the associated WAR. It will be deleted. Expanding fuseki.war into /home/fabio/Documentos/heroku/deploy-war/helloworld/target/tomcat.8080/webapps/expanded Adding Context for /home/fabio/Documentos/heroku/deploy-war/helloworld/target/tomcat.8080/webapps/expanded jan 25, 2021 5:17:36 PM org.apache.coyote.AbstractProtocol init INFORMAÇÕES: Initializing ProtocolHandler ["http-nio-8080"] jan 25, 2021 5:17:36 PM org.apache.catalina.core.StandardService startInternal INFORMAÇÕES: Starting service [Tomcat] jan 25, 2021 5:17:36 PM org.apache.catalina.core.StandardEngine startInternal INFORMAÇÕES: Starting Servlet engine: [Apache Tomcat/9.0.41] jan 25, 2021 5:17:37 PM org.apache.catalina.startup.ContextConfig getDefaultWebXmlFragment INFORMAÇÕES: No global web.xml found jan 25, 2021 5:17:40 PM org.apache.jasper.servlet.TldScanner scanJars INFORMAÇÕES: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time. [2021-01-25 17:17:41] Config INFO FUSEKI_HOME=unset [2021-01-25 17:17:41] Config INFO FUSEKI_BASE=/etc/fuseki [2021-01-25 17:17:41] Server ERROR Exception in server initialization org.apache.jena.fuseki.FusekiConfigException: Failed to create directory: /etc/fuseki at org.apache.jena.fuseki.webapp.FusekiWebapp.ensureDir(FusekiWebapp.java:372) ~[jena-fuseki-webapp-3.17.0.jar:3.17.0] at org.apache.jena.fuseki.webapp.FusekiWebapp.formatBaseArea(FusekiWebapp.java:145) [jena-fuseki-webapp-3.17.0.jar:3.17.0] at org.apache.jena.fuseki.webapp.ShiroEnvironmentLoader.contextInitialized(ShiroEnvironmentLoader.java:50) [jena-fuseki-webapp-3.17.0.jar:3.17.0] at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4716) [webapp-runner.jar:?] at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5177) [webapp-runner.jar:?] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) [webapp-runner.jar:?] at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1384) [webapp-runner.jar:?] at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1374) [webapp-runner.jar:?] at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?] at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) [webapp-runner.jar:?] at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140) [?:?] at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909) [webapp-runner.jar:?] at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:843) [webapp-runner.jar:?] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) [webapp-runner.jar:?] at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1384) [webapp-runner.jar:?] at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1374) [webapp-runner.jar:?] at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?] at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) [webapp-runner.jar:?] at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140) [?:?] at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909) [webapp-runner.jar:?] at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:262) [webapp-runner.jar:?] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) [webapp-runner.jar:?] at org.apache.catalina.core.StandardService.startInternal(StandardService.java:434) [webapp-runner.jar:?] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) [webapp-runner.jar:?] at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:930) [webapp-runner.jar:?] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) [webapp-runner.jar:?] at org.apache.catalina.startup.Tomcat.start(Tomcat.java:486) [webapp-runner.jar:?] at webapp.runner.launch.Main.main(Main.java:289) [webapp-runner.jar:?] jan 25, 2021 5:17:41 PM org.apache.catalina.core.StandardContext listenerStart GRAVE: Exception sending context initialized event to listener instance of class [org.apache.jena.fuseki.webapp.ShiroEnvironmentLoader] org.apache.jena.fuseki.FusekiConfigException: Failed to create directory: /etc/fuseki at org.apache.jena.fuseki.webapp.FusekiWebapp.ensureDir(FusekiWebapp.java:372) at org.apache.jena.fuseki.webapp.FusekiWebapp.formatBaseArea(FusekiWebapp.java:145) at org.apache.jena.fuseki.webapp.ShiroEnvironmentLoader.contextInitialized(ShiroEnvironmentLoader.java:50) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4716) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5177) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1384) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1374) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140) at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909) at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:843) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1384) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1374) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140) at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909) at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:262) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) at org.apache.catalina.core.StandardService.startInternal(StandardService.java:434) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:930) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) at org.apache.catalina.startup.Tomcat.start(Tomcat.java:486) at webapp.runner.launch.Main.main(Main.java:289) [2021-01-25 17:17:41] Server ERROR Failed to initialize : Server not running jan 25, 2021 5:17:41 PM org.apache.catalina.core.StandardContext startInternal GRAVE: One or more listeners failed to start. Full details will be found in the appropriate container log file jan 25, 2021 5:17:41 PM org.apache.catalina.core.StandardContext startInternal GRAVE: Context [] startup failed due to previous errors SEVERE: Context [] failed in [org.apache.catalina.core.StandardContext] lifecycle. Allowing Tomcat to shutdown. jan 25, 2021 5:17:41 PM org.apache.catalina.core.ApplicationContext log INFORMAÇÕES: Cleaning up Shiro Environment WARNING: An illegal reflective access operation has occurred WARNING: Illegal reflective access by org.apache.catalina.loader.WebappClassLoaderBase (file:/home/fabio/Documentos/heroku/deploy-war/helloworld/target/dependency/webapp-runner.jar) to field java.io.ObjectStreamClass$Caches.localDescs WARNING: Please consider reporting this to the maintainers of org.apache.catalina.loader.WebappClassLoaderBase WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations WARNING: All illegal access operations will be denied in a future release jan 25, 2021 5:17:41 PM org.apache.coyote.AbstractProtocol start INFORMAÇÕES: Starting ProtocolHandler ["http-nio-8080"]
fuseki.war
requer leitura e escrita em /etc/fuseki
, que é uma pasta no sistema de arquivos. Heroku não tem essa pasta, então a execução é abortada. Algumas pessoas tentaram contornar isso, aparentemente, sem sucesso.
Fuseki e Spring Boot
Troca de email de março de 2020, contém informação interessante sobre jetty e fuseki-main: http://mail-archives.apache.org/mod_mbox/jena-users/202003.mbox/%[email protected]%3E
Fuseki/Jena e Maven
- https://jena.apache.org/download/maven.html
- https://search.maven.org/artifact/org.apache.jena/jena-fuseki-webapp/3.17.0/jar
- https://jena.apache.org/documentation/fuseki2/fuseki-webapp.html
- POM do fuseki-server: https://github.com/apache/jena/blob/master/jena-fuseki2/jena-fuseki-server/pom.xml
Fuseki e Sistema de Arquivos
Configuração do fuseki-server
Raiz da documentação do Fuseki
https://devcenter.heroku.com/articles/configuring-war-deployment-with-the-heroku-toolbelt
Falta implantar no Heroku. nota antes de implantar no heroku não tem pasta .git
.
No futuro melhorarei a apresentação desta seção. Seguir o tutorial para implantar WAR através de Webapp-runner-FIM
Entrar na pasta do app que quer compilar e executar: mvn install
Entrar na pasta do app que quer executar e executar: heroku local:start
Não posso ter dois consoles executando simultaneamente.
Talvez seja possível criar um war do Fuseki para Heroku: https://devcenter.heroku.com/articles/war-deployment
Nos documentos, está escrito que usa Spring Boot (entre outros). Já vi isso em Ontmalizer e na IC do Joedson, então fui ver o que é:
Clonei de github mas dei push em heroku. Isto quer dizer que substituí a referência para o repositório remoto do github para o heroku?? Esse heroku em especial é meu, privado? Como a operação é transparente, ficam essas perguntas.
Isto poderia gerar interferência, por exemplo, se uso um github remoto para manter código e colaboradores e implanto usando heroku em outro remoto.
Consegui fechar uma história sobre Heroku, mas estou com várias outras (derivadas) abertas.