Johnathan Gilday
Next Century Corporation
2016-07-14
We need to optimize the way we build and deploy these services. Abandoning the shared application container is one way
@WebListener
public class AppInitializer implements ServletContextListener {
@Override
public void contextInitialized(final ServletContextEvent sce) {
// container calls this method to initialize app
}
@Override
public void contextDestroyed(final ServletContextEvent sce) {
// container calls this method to shutdown app
}
}
@WebServlet(name = "my-servlet", urlPatterns = "/my-servlet")
public class MyServlet extends HttpServlet {
@Override
public void doGet(final HttpServletRequest req, final HttpServletResponse resp) {
// container calls this method on incoming request
}
}
Delivers a packaged application with dependencies outside of those provided by the container
Delivers a configuration files and documentation for running the service
/**
* Point of entry. Configure and start app
*/
public class App {
public static void main(final String[] args) {
// configure application
// register signal handlers if desired
// run web server until app terminates
}
}
public static void main(final String[] args) {
// start jetty
logger.info("listening on port {}", port);
final ResoureConfig rc = ResourceConfig.forApplication(app);
final Server server = JettyHttpContainerFactory.createServer(baseUri, rc);
try {
server.start();
server.join();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
JettyHttpContainerFactory
$ gradle shadowJar
$ java -jar build/libs/my-app.jar
listening on port 8000
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-5level %logger{5} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
[Unit]
Description=my-app service
[Service]
EnvironmentFile=-/etc/sysconfig/my-app
ExecStart=/usr/bin/java \$JVM_OPTS -jar /opt/my-app/my-app-${version}-all.jar
User=my-app
Restart=on-failure
[Install]
WantedBy=multi-user.target
[vagrant@localhost ~]$ journalctl -fu how-to-microservice
-- Logs begin at Thu 2016-07-14 00:07:10 UTC. --
Jul 14 00:08:44 localhost.localdomain systemd[1]: Started how-to-microservice service.
Jul 14 00:08:44 localhost.localdomain systemd[1]: Starting how-to-microservice service...
Jul 14 00:08:44 localhost.localdomain java[11726]: 2016-07-14T00:08:44,718Z INFO c.j.App - listening on port 8000
$ rpm -qlp build/distributions/how-to-microservice-0.0.4-1.e7.noarch.rpm
/etc/how-to-microservice
/etc/how-to-microservice/settings.conf
/etc/sysconfig
/etc/sysconfig/how-to-microservice
/etc/systemd
/etc/systemd/system
/etc/systemd/system/how-to-microservice.service
/opt/how-to-microservice
/opt/how-to-microservice/how-to-microservice-0.0.4-SNAPSHOT-all.jar
/opt/how-to-microservice/settings.conf
task rpm(type: Rpm) {
it.dependsOn shadowJar
packageName = project.name
version = '0.0.4'
release = '1.e7'
os = LINUX
requires('java-1.8.0-openjdk')
...
Vagrant.configure(2) do |config|
config.vm.box = "geerlingguy/centos7"
...
config.vm.provision "shell", inline: <<-SHELL
sync_dir=/vagrant
rpm=($sync_dir/build/distributions/*.rpm)
if [ ! -f $rpm ]; then
echo "how-to-microservice RPM not found"
exit 1
fi
sudo yum erase -y how-to-microservice
sudo yum install -y $rpm
sudo systemctl restart how-to-microservice
SHELL
end
vagrant destroy -f && vagrant up
FROM java:8
MAINTAINER Johnathan Gilday
COPY ./build/libs/how-to-microservice.jar /opt/how-to-microservice/
EXPOSE 8000
WORKDIR /opt/how-to-microservice
CMD ["java", "-jar", "how-to-microservice.jar"]
Sample self-contained jersey service
https://github.com/gilday/how-to-microservice
Gradle plugin for building "fat jars"
https://github.com/johnrengelman/shadow
Netflix OSS Gradle plugins (including gradle-os-package)
https://nebula-plugins.github.io/
Nexus yum repository hosting
https://books.sonatype.com/nexus-book/reference/yum-configuration.html
Vagrant shell provisioner
https://www.vagrantup.com/docs/provisioning/shell.html