Agenda
- Deplyoment Automation (Beanstalk & Gradle)
- Log Monitoring (Sentry)
- Application Performance Monitoring (NewRelic)
Sample Application for Deployment
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk install grails
grails create-app dinte2018
cd dinte2018
# inside grails-app/conf/application.yml
# 1) remove environments.production.dataSource.properties
# 2) update environments.production.dataSource.url to use in-memory database
# 3) set environments.production.dataSource.dbCreate to update
# before creating the WAR
grails war
AWS Elastic Beanstalk
AWS Elastic Beanstalk
AWS Elastic Beanstalk is an easy-to-use service for deploying and scaling web applications and services developed with Java
Beanstalk Application
Beanstalk Application
Beanstalk Application
Beanstalk Application
Beanstalk Application
Beanstalk Application
Beanstalk Application
Beanstalk Application
Deployment Automation
Gradle Beanstalk Plugin
Gradle Beanstalk Plugin
plugins {
id "fi.evident.beanstalk" version "0.2.0"
}
// ...
// version needs to be unique during deployment but plugin supports snapshots
version = "0.1-SNAPSHOT"
// ...
beanstalk {
s3Endpoint = "s3-eu-west-1.amazonaws.com"
beanstalkEndpoint = "elasticbeanstalk.eu-west-1.amazonaws.com"
deployments {
gr8war {
file = tasks.war
application = 'dinte2018'
environment = 'Dinte2018-env'
}
}
}
Gradle Beanstalk Plugin
./gradlew deployGr8war
AWS Credentials
AWS Credentials
AWS Credentials
AWS Credentials
AWS Credentials
pip install awscli --upgrade --user
aws configure
# AWS Access Key ID [****************C7YQ]: AAAAAAA
# AWS Secret Access Key [****************ci+o]: BBBBBBBBBBBB
# Default region name [eu-west-1]: eu-west-1
# Default output format [None]:
./gradlew deployGr8war
JAR Deployments
JAR Deployments
// uncomment/remove "war" plugin
// apply plugin:"war"
// ...
deployments {
gr8jar {
file = tasks.jar
application = 'dinte2018'
environment = 'gr8jar'
}
}
// run "assemble" before deployment to create fat jar
tasks.withType(fi.evident.gradle.beanstalk.DeployTask) {
dependsOn assemble
}
JAR Deployments
# add following into grails-app/conf/application.yml
---
environments:
production:
server:
port: 5000
JAR Deployments
JAR Deployments
JAR Deployments
JAR Deployments
JAR Deployments
JAR Deployments
./gradlew deployGr8jar
ZIP Deployments
Grails with File Upload
Grails with File Upload
Grails with File Upload
Grails with File Upload
Grails with File Upload
Grails with File Upload
Grails with File Upload
Grails with File Upload
AWS Elastic Beanstalk
AWS Elastic Beanstalk is an easy-to-use service for deploying and scaling web applications and services developed with Java, .NET, PHP, Node.js, Python, Ruby, Go, and Docker on familiar servers such as Apache, Nginx, Passenger, and IIS.
NGINX EVERYWHERE
# Elastic Beanstalk Nginx Configuration File in src/main/eb/.ebextensions/nginx/nginx.conf
user nginx;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
worker_processes auto;
worker_rlimit_nofile 19200;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
include conf.d/*.conf;
map $http_upgrade $connection_upgrade {
default "upgrade";
}
server {
listen 80 default_server;
access_log /var/log/nginx/access.log main;
client_header_timeout 60;
client_body_timeout 60;
keepalive_timeout 60;
gzip off;
gzip_comp_level 4;
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
# Include the Elastic Beanstalk generated locations
include conf.d/elasticbeanstalk/*.conf;
# Increase upload body size
client_max_body_size 25m;
}
}
Elastic Beanstalk Extensions
Elastic Beanstalk Extensions
task beanstalkArchive(type: Zip, dependsOn: assemble) {
from 'src/main/eb'
from tasks.jar
}
beanstalk {
s3Endpoint = "s3-eu-west-1.amazonaws.com"
beanstalkEndpoint = "elasticbeanstalk.eu-west-1.amazonaws.com"
deployments {
gr8jar {
file = tasks.beanstalkArchive
application = 'dinte2018'
environment = 'gr8jar'
}
}
}
Log Monitoring
Log Monitoring
Log Monitoring
What is your favorite way how to break the application?
String Constraints Test
String Constraints Test
String Constraints Test
Sentry
Sentry
Sentry
Grails Sentry Plugin
Grails Sentry Plugin
dependencies {
compile 'org.grails.plugins:sentry:11.7.4'
}
---
environments:
production:
server:
port: 5000
grails:
plugin:
sentry:
dsn: ${SENTRY_DSN}
Grails Sentry Plugin
Grails Sentry Plugin
Grails Sentry Plugin
String Constraints Test
Sentry with Spring Security
# grails-app/conf/application.yml
---
environments:
production:
server:
port: 5000
grails:
plugin:
sentry:
dsn: ${SENTRY_DSN}
# enables Spring Security integration
springSecurityUser: true
Sentry with Spring Security
Application Performance Monitoring
NewRelic
NewRelic
NewRelic
NewRelic & Grails
Grails NewRelic Plugin
Grails NewRelic Plugin
<!doctype html>
<!-- grails-app/views/layouts/main.gsp -->
<html lang="en" class="no-js">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<newrelic:browserTimingHeader/>
<!-- ... -->
</head>
<body>
<!-- ... -->
<newrelic:browserTimingFooter/>
</body>
</html>
NewRelic & Beanstalk
NewRelic on Beanstalk
└── src
└── main
└── eb
├── .ebextensions
│ ├── app.config
│ ├── files
│ │ ├── newrelic.jar
│ │ └── newrelic.yml.sh
│ ├── newrelic.sh
│ └── nginx
│ └── nginx.conf
└── Procfile
NewRelic on Beanstalk
Grails NewRelic Plugin
NewRelic on Beanstalk
NewRelic on Beanstalk
# src/main/eb/.ebextensions/files/newrelic.yml.sh
cat << EOF
# apply defaults
common: &default_settings
# apply custom settings
license_key: '$NR_LICENSE'
enable_auto_transaction_naming: false
app_name: $NR_APPNAME
EOF
NewRelic on Beanstalk
#!/bin/sh
# src/main/eb/.ebextensions/newrelic.sh
# New Relic (Application monitoring)
mkdir /var/lib/newrelic
mv ./.ebextensions/files/newrelic*.jar /var/lib/newrelic/
bash ./.ebextensions/files/newrelic.yml.sh > /var/lib/newrelic/newrelic.yml
# New Relic deployment event
export AP_VERSION=`cat ./version`
java -Xms64m -Xmx124m -jar /var/lib/newrelic/newrelic.jar deployment --revision=$AP_VERSION
task prepareBeanstalkFiles() {
inputs.property('version', project.version)
outputs.file("$buildDir/beanstalk")
doLast {
file("$buildDir/beanstalk").mkdirs()
file("$buildDir/beanstalk/version").text = project.version
}
}
task beanstalkArchive(type: Zip, dependsOn: [assemble, prepareBeanstalkFiles]) {
from 'src/main/eb'
from "$buildDir/beanstalk" // include generated version file
from tasks.jar
}
NewRelic on Beanstalk
# src/main/eb/.ebextensions/app.config
container_commands:
newrelic:
command: "bash -x .ebextensions/newrelic.sh"
NewRelic on Beanstalk
# src/main/eb/Procfile
web: java -javaagent:/var/lib/newrelic/newrelic.jar -jar dinte2018.jar
jar {
archiveName = 'dinte2018.jar'
}
NewRelic on Beanstalk
NewRelic on Beanstalk
NewRelic on Beanstalk
NewRelic on Beanstalk
NewRelic on Beanstalk
NewRelic & Infrastructure
NewRelic Infrastructure
# src/main/eb/.ebextensions/newrelic-infra.sh
echo "license_key: $NR_LICENSE" | sudo tee -a /etc/newrelic-infra.yml
echo "display_name: `hostname`" | sudo tee -a /etc/newrelic-infra.yml
sudo curl -o /etc/yum.repos.d/newrelic-infra.repo \
https://download.newrelic.com/infrastructure_agent/linux/yum/el/6/x86_64/newrelic-infra.repo
sudo yum -q makecache -y --disablerepo='*' --enablerepo='newrelic-infra'
sudo yum install newrelic-infra -y
# src/main/eb/.ebextensions/app.config
container_commands:
newrelic:
command: "bash -x .ebextensions/newrelic.sh"
newrelic-infra:
command: "bash -x .ebextensions/newrelic-infra.sh"
NewRelic Infrastructure
NewRelic & NGINX
NewRelic NGINX Plugin
# src/main/eb/.ebextensions/app.config
files:
"/etc/yum.repos.d/nginx.repo":
content: |
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/rhel/6/$basearch/
gpgcheck=0
enabled=1
container_commands:
newrelic:
command: "bash -x .ebextensions/newrelic.sh"
newrelic-infra:
command: "bash -x .ebextensions/newrelic-infra.sh"
nginx-nr-agent:
command: "bash -x .ebextensions/nginx-nr-agent.sh"
NewRelic NGINX Plugin
# src/main/eb/.ebextensions/nginx-nr-agent.sh
sudo yum install nginx-nr-agent -y
bash ./.ebextensions/files/nginx-nr-agent.ini.sh > /etc/nginx-nr-agent/nginx-nr-agent.ini
sudo service nginx-nr-agent start
NewRelic NGINX Plugin
# src/main/eb/.ebextensions/files/nginx-nr-agent.ini.sh
cat << EOF
# global settings
[global]
newrelic_license_key=$NR_LICENSE
poll_interval=60
# logging settings
[loggers]
keys=root
[handlers]
keys=consoleHandler,fileHandler
[formatters]
keys=simpleFormatter
[logger_root]
level=DEBUG
handlers=consoleHandler,fileHandler
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)
[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=simpleFormatter
args=('/var/log/nginx-nr-agent.log','a',)
[formatter_simpleFormatter]
format=%(asctime)s %(name)s [%(levelname)s]: %(message)s
datefmt=
# data sources settings
[$NR_APPNAME]
name=$NR_APPNAME
url=http://127.0.0.1/nginx_status
EOF
NewRelic NGINX Plugin
# src/main/eb/.ebextensions/nginx/nginx.conf
# ...
server {
# ...
client_max_body_size 25m;
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
}
# ...
NewRelic NGINX Plugin
NewRelic & Metrics
Dropwizard Metrics Plugin
Dropwizard Metrics Plugin
dependencies {
// ...
compile 'org.grails.plugins:newrelic:4.0.1'
compile 'com.palominolabs.metrics:metrics-new-relic:1.0.5'
compile 'org.grails.plugins:dropwizard-metrics:1.0.0.M3'
}
Dropwizard Metrics Plugin
// grails-app/init/dinte2018/BootStrap.groovy
package dinte2018
import com.codahale.metrics.MetricFilter
import com.codahale.metrics.MetricRegistry
import com.palominolabs.metrics.newrelic.AllEnabledMetricAttributeFilter
import com.palominolabs.metrics.newrelic.NewRelicReporter
import java.util.concurrent.TimeUnit
class BootStrap {
MetricRegistry metricRegistry
def init = { servletContext ->
new NewRelicReporter(
metricRegistry,
'Deployment is not the End Metrics',
MetricFilter.ALL,
new AllEnabledMetricAttributeFilter(),
TimeUnit.SECONDS,
TimeUnit.MILLISECONDS,
'dinte2018.'
).start(1, TimeUnit.MINUTES)
}
def destroy = { }
}
Dropwizard Metrics Plugin
// grails-app/services/dinte2018/UploadRestaurantFeaturedImageService.groovy
package dinte2018
import grails.plugin.dropwizard.metrics.meters.Metered
class UploadRestaurantFeaturedImageService {
def restaurantGormService
@Metered(value='uploadFeatureImage', useClassPrefix = true)
Restaurant uploadFeatureImage(FeaturedImageCommand cmd) {
byte[] bytes = cmd.featuredImageFile.bytes
String contentType = cmd.featuredImageFile.contentType
restaurantGormService.updateRestaurantFeaturedImage(
cmd.id,
cmd.version,
bytes,
contentType
)
}
}
Dropwizard Metrics Plugin
Dropwizard Metrics Plugin
Dropwizard Metrics Plugin
Dropwizard Metrics Plugin
Dropwizard Metrics Plugin
On recrute !
Deployment is not the End
By musketyr
Deployment is not the End
- 2,578