Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Minha aplicação Java vai pra Nuvem. E agora?

Minha aplicação Java vai pra Nuvem. E agora?

Estamos acostumados a trabalhar com Java em ambiente local ou em algum servidor de desenvolvimento. Nesta talk mostrei os principais desafios encontrados quando utilizamos Java em um cenário de Cloud, utilizando um PaaS de mercado (Heroku).

Palestra no evento do SOUJava realizado na Locaweb.

Felipe Mamud

June 13, 2015
Tweet

More Decks by Felipe Mamud

Other Decks in Programming

Transcript

  1. Para convencer o gerente... Reduzir o custo? A galera toda

    está indo pra nuvem, demoro! +Escalabilidade? +Disponibilidade? +Elasticidade? Otimização de recursos? Serviços prontos para utilização? Qualquer tipo de nuvem me atende, ta sussa! Qualquer fornecedor de nuvem me atende, suave! Limitações e vendor lock-in. Bora! Não vai influenciar em nada meu trampo, é nois!
  2. Algumas diferenças • Somente Embeddable Application Servers, sendo possível deploy

    do .war (Tomcat, Jetty, JBoss or GlassFish, etc.); • Bibliotecas como stack de Servlet, JSP, drivers JDBC e outras bibliotecas Java EE são linkadas na aplicação usando gerenciamento de dependência; • Configuração de serviço baseado em variável de ambiente (Ex: DATABASE_URL); • Deploy via Git workflow → • Gerenciamento de infra e aplicação via ferramenta de CLI [Heroku Toolbelt]. (Ex. start/stop, clustering, logs). $ git push heroku master
  3. Particularidades • Suporte para Java 6, 7 e 8; •

    Dynos → Lightweight linux container. (Web, Worker e One-off); • Arquitetura share-nothing. (Não devem haver sessões stateful); • Clustering via CLI → • Load-balance automático; • Failover com detecção de falha em nó de aplicativo, em seguida, tentativa de reinício; $ heroku ps:scale web=2 worker=4 ...
  4. E para começar? • Java instalado; • Maven 3.x instalado;

    • Criar uma conta free no Heroku; • Baixar e instalar o Heroku Toolbelt;
  5. Login no Heroku Lá vamos nós... Fork de um projeto

    Java Blank $ heroku login Enter your Heroku credentials. Email: [email protected] Password: $ git clone https://github.com/heroku/java-getting-started.git $ cd java-getting-started
  6. $ cat Procfile web: java -cp target/classes:target/dependency/* Main Estrutura do

    projeto $ cat system.properties java.runtime.version=1.8 $ cat pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http: //maven.apache.org/maven-v4_0_0.xsd"> ...
  7. Criando a aplicação no Heroku $ heroku create Creating soujava-locaweb-13062015...

    done, stack is cedar-14 http://soujava-locaweb-13062015.herokuapp.com/ | https://git.heroku.com/soujava-locaweb-13062015.git Git remote heroku added Criação
  8. Fazendo o deploy Deploy $ git push heroku master Initializing

    repository, done. Counting objects: 68, done. Delta compression using up to 4 threads. Compressing objects: 100% (19/19), done. Writing objects: 100% (68/68), 7.07 KiB | 0 bytes/s, done. Total 68 (delta 22), reused 65 (delta 22) -----> Java app detected -----> Installing OpenJDK 1.8... done -----> Installing Maven 3.3.1... done -----> Executing: mvn -B -DskipTests=true clean install ....
  9. O que acontece no deploy? Slugs são copias comprimidas e

    pré-empacotadas de sua aplicação otimizada para a distribuição para o dyno manager. (Limite de 15m na compilação). 1. Cria um novo checkout de HEAD oriundo do branch master; 2. Remove arquivos não utilizados, incluindo diretórios .git, arquivos .gitmodules, qualquer arquivo no tmp, e qualquer entrada especificada em um arquivo top-level .slugignore. 3. Download, build e install das dependências locais, conforme especificado no arquivo de build (Ex.: Gemfile, package.json, requirements.txt, pom.xml, etc.) com a ferramenta de gerenciamento de dependência suportada pela linguagem utilizada (ex.: Bundler, npm, pip, Maven). 4. Empacotamento final do slug file.
  10. Garantindo pelo menos, uma instância da aplicação em execução: Finalizando

    Para finalizar… abrir a aplicação no browser. $ heroku ps:scale web=1 $ heroku open
  11. import org.eclipse.jetty.server.Server; import org.eclipse.jetty.webapp.WebAppContext; public class StartWebApp { public static

    void main(String[] args) throws Exception { String portStr = System.getenv("PORT"); int port = (portStr == null) ? 8085 : Integer.parseInt(portStr); Server server = new Server(port); WebAppContext webapp = new WebAppContext(); webapp.setContextPath("/"); // change the name of the war as needed. webapp.setWar("target/classes/mywebapp.war"); server.setHandler(webapp); server.start(); server.join(); } } E deploy com WAR? Fonte: http://ollivander.franzoni.eu/2011/10/20/deploy-any-java-webapp-via-war-to-heroku/
  12. Visualizando logs Outros comandos úteis 1/3 $ heroku ps ===

    web (1X): `java $JAVA_OPTS -cp target/classes:target/dependency/* Main` web.1: up 2015/06/13 08:45:07 (~ 2m ago) Verificando quantos dynos estão em execução $ heroku logs --tail 2015-06-13T08:55:07.254053+00:00 heroku[web.1]: State changed from starting to up 2015-06-13T08:55:05.214125+00:00 heroku[web.1]: Starting process with command `java -Xmx384m -Xss512k -XX:+UseCompressedOops -cp target/classes:target/dependency/* Main` ...
  13. Visualizar todos os releases Outros comandos úteis 2/3 $ heroku

    releases:rollback v102 Rolling back demoapp... done, v102 $ heroku releases == demoapp Releases v104 Rollback to v102 [email protected] 2013/01/31 14:11:33 (~15s ago) v103 Deploy 582fc95 [email protected] 2013/01/31 12:15:35 v102 Deploy 990d916 [email protected] 2013/01/31 12:01:12 Executando um rollback $ heroku releases == demoapp Releases v103 Deploy 582fc95 [email protected] 2013/01/31 12:15:35 v102 Deploy 990d916 [email protected] 2013/01/31 12:01:12
  14. Acessando a aplicação via bash Outros comandos úteis 3/3 $

    heroku addons:create rediscloud:25 // using var REDISCLOUD_URL Adicionando add-ons na aplicação através do $ heroku run bash Running `bash` attached to terminal... up, run.8963 ~ $ ls
  15. Utilizando o foreman E rodar a aplicação local? $ foreman

    start web 07:45:16 web.1 | started with pid 2071 07:45:16 web.1 | 2015-06-13 07:45:16.329:INFO:oejs.Server:jetty-7.6.0.v20120127 07:45:16 web.1 | 2015-06-13 07:45:16.378:INFO:oejsh.ContextHandler:started o.e.j.s. ServletContextHandler{/,null} 07:45:16 web.1 | 2015-06-13 07:45:16.411:INFO:oejs.AbstractConnector:Started [email protected]:5000
  16. E as variáveis de config? private void showHome(HttpServletRequest req, HttpServletResponse

    resp) throws ServletException, IOException { // Energy is compatible with mass (E=mc2) RelativisticModel.select(); String energy = System.getenv().get("ENERGY"); Amount<Mass> m = Amount.valueOf(energy).to(KILOGRAM); resp.getWriter().print("E=mc^2: " + energy + " = " + m); } $ heroku config GITHUB_USERNAME: joesmith OTHER_VAR: production Limite de 16kb para cada aplicação.
  17. E acesso ao DB? private Connection getConnection() throws URISyntaxException, SQLException

    { URI dbUri = new URI(System.getenv("DATABASE_URL")); String username = dbUri.getUserInfo().split(":")[0]; String password = dbUri.getUserInfo().split(":")[1]; int port = dbUri.getPort(); String dbUrl = "jdbc:postgresql://" + dbUri.getHost() + ":" + port + dbUri.getPath(); return DriverManager.getConnection(dbUrl, username, password); } $ heroku config === soujava-locaweb-13062015 Config Vars DATABASE_URL: postgres://qplhasewkhqyxp: YXDPSRus9MrU4HglCPzjhOevee@ec2-54-204-47-58.compute-1.amazonaws.com: 5432/dc9qsdnghia6v1
  18. DB Pool? import java.sql.*; import org.apache.commons.dbcp.*; private BasicDataSource connectionPool; public

    configureDBPool() throws URISyntaxException, SQLException { URI dbUri = new URI(System.getenv("DATABASE_URL")); String dbUrl = "jdbc:postgresql://" + dbUri.getHost() + dbUri.getPath(); connectionPool = new BasicDataSource(); if (dbUri.getUserInfo() != null) { connectionPool.setUsername(dbUri.getUserInfo().split(":")[0]); connectionPool.setPassword(dbUri.getUserInfo().split(":")[1]); } connectionPool.setDriverClassName("org.postgresql.Driver"); connectionPool.setUrl(dbUrl); connectionPool.setInitialSize(1); // to set the initial size of the pool. }
  19. "For I am persuaded, that neither death, nor life, nor

    angels, nor principalities, nor powers, nor things present, nor things to come, Nor height, nor depth, nor any other creature, shall be able to separate us from the love of God, which is in Christ Jesus our Lord." (Romanos 8:38-39) FTD GROUP, JOIN US!