Gradle 3.2.1



위 "test-ear-dir" 디렉토리와 같이 ear 구조로 배치되어 있는 상태에서 gradle + ant 를 활용해 패키징 한다. 


task dirEar {
doLast {
println 'aa'
ant.ear(destfile: 'build/test.ear',
appxml: 'build/test-ear-dir/META-INF/application.xml') {
fileset (dir: 'build/test-ear-dir')
}
}
}


Gradle 이용한 간단한 원격 배포 셈플링


그룹별 병렬? 배포 - WAS Instance 가 늘더라도 배포 시간 절약

  1. WAS 유입 차단 -> 5초대기 -> WAS 중지
  2. 소스 배포 -> 소스 압축 풀기 및 설정
  3. WAS 기동
  4. 필수 서비스 체크(CURL)
  5. WAS 유입 활성화


빌드 파일과 별도 분리 해도 되고...(분리된 파일을 Jenkins에서 실행)


clean build remoteDeploy


.. .. apply plugin: 'org.hidetake.ssh' .. .. buildscript { repositories { jcenter() } dependencies { classpath 'org.hidetake:gradle-ssh-plugin:2.4.2' } } task remoteDeploy << { def startTime = System.currentTimeMillis() println "project: [$project]" def PROJECT_NM = project.name def DEPLOY_SERVERS = [] if( "$targetServer" == "dev" ){ DEPLOY_SERVERS = [ group1: [ ], ] } else if( "$targetServer" == "stage" ){ DEPLOY_SERVERS = [ group1: [ ], ] } else if( "$targetServer" == "real" ){ DEPLOY_SERVERS = [ group1: [ [host: "dkwas01", user: "tomcat", wasHome: "/usr/local/tomcat/domains/test11", wasDomain: "test11", webRoot: "/data/webroot/app-test", isWait: true,], [host: "dkwas02", user: "tomcat", wasHome: "/usr/local/tomcat/domains/test21", wasDomain: "test21", webRoot: "/data/webroot/app-test", isWait: true,], ], group2: [ [host: "dkwas03", user: "tomcat", wasHome: "/usr/local/tomcat/domains/test31", wasDomain: "test31", webRoot: "/data/webroot/app-test", isWait: true,], [host: "dkwas04", user: "tomcat", wasHome: "/usr/local/tomcat/domains/test41", wasDomain: "test41", webRoot: "/data/webroot/app-test", isWait: true,], ], ] } DEPLOY_SERVERS.eachWithIndex { gItem, gIdx ---> logInfo(DEPLOY_SERVERS, gItem, gIdx, null, null, "START") gItem.value.eachWithIndex() { hItem, hIdx -> def remoteUser = hItem.user def remoteHost = hItem.host def isWait = hItem.isWait def catalinaBase = hItem.wasHome def wasDomain = hItem.wasDomain def webRoot = hItem.webRoot def warPath = webRoot + "/../" + PROJECT_NM def remoteServer = [host: remoteHost, user: remoteUser, identity: file("${System.properties['user.home']}/.ssh/id_rsa")] ssh.run { session(remoteServer) { logInfo(DEPLOY_SERVERS, gItem, gIdx, hItem, hIdx, "HTTPD(JK_MOD) BLOCK -> WAS SHUTDOWN") // 고객유입 차단 -> WAS 중지 execute "cd $catalinaBase; ./shutdown.sh " + (isWait?'wait update 5':'') logInfo(DEPLOY_SERVERS, gItem, gIdx, hItem, hIdx, "WAR REMOTE COPY") put from: war.archivePath.path, into: warPath execute "rm -Rf " + webRoot + "/*" execute "cd " + webRoot + "; jar xf " + warPath execute "chmod -Rf 755 " + webRoot + "/*" logInfo(DEPLOY_SERVERS, gItem, gIdx, hItem, hIdx, "WAR START (HTTPD(JK_MOD) BLOCKING)") // WAS 기동 (고객 유입은 차단상태) execute "cd $catalinaBase; ./start.sh" } } } gItem.value.eachWithIndex() { hItem, hIdx -> def remoteUser = hItem.user def remoteHost = hItem.host def catalinaBase = hItem.wasHome def isWait = hItem.isWait def wasDomain = hItem.wasDomain def remoteServer = [host: remoteHost, user: remoteUser, identity: file("${System.properties['user.home']}/.ssh/id_rsa")] ssh.run { session(remoteServer) { logInfo(DEPLOY_SERVERS, gItem, gIdx, hItem, hIdx, "CHECK SERVICE") while (true) { sleep(2000) def resultStr = execute "cd $catalinaBase; ./checkService.sh" if (resultStr.contains(wasDomain) && resultStr.contains("SERVICE CHECK ERROR") == false) { break } print "." } logInfo(DEPLOY_SERVERS, gItem, gIdx, hItem, hIdx, "HTTPD(JK_MOD) FLOW") // 고객 유입 execute "cd $catalinaBase; ./httpd.sh start" } } } logInfo(DEPLOY_SERVERS, gItem, gIdx, null, null, "END") } def totalExecTime = (System.currentTimeMillis() - startTime) / 1000 println "==================== TOTAL EXEC TIME: " + (totalExecTime) + "s ====================" } static logInfo(deployServers, gItem, gIdx, hItem, hIdx, msg) { println("==================== [GROUP $gItem.key " + (gIdx + 1) + "/" + deployServers.size() + (hItem?" " + (hIdx + 1) + "/" + gItem.value.size() + " $hItem.host:$hItem.wasDomain] ":" ") + msg + " ====================" ) }


일반적으로 Jenkins나 SSH(SCP) 등을 이용해서 원격지 배포 시 순차 배포 하게 된다.

하지만 원격지 서버의 수가 많으면 (1대 배포 시간 * 배포 서버 수)가 되어 배포 시간이 증가하게 된다.

급하게 배포하거나, 롤백 하는 상황에서 배포 시간이 증가하게 되면 빠른 복구가 힘들어 진다.

그에 따라서 약 2그룹으로 나누고, 각 그굽을 병렬로 처리 할 수 있도록 해보자.


하지만 이 방법은 2그룹 중 1그룹으로도 고객 서비스가 원할 해야 한다는 보장이 있어야 하며, 결국 오버스펙으로 운영 해야 한다는 말..


(war 배포아닌 파일 묶음 배포 방식)



Gradle 에서 jar를 생성할때 의존된 jar들 포함시켜서 말고 싶을때가 있다.


https://github.com/musketyr/gradle-fatjar-plugin


buildscript {
    repositories {
        jcenter()
    }

    dependencies {
        classpath 'eu.appsatori:gradle-fatjar-plugin:0.3'
    }
}

apply plugin: 'eu.appsatori.fatjar'

Gradle

[build.gradle]

dependencies {
	compile 'com.yahoo.platform.yui:yuicompressor:2.4.8'
}

apply plugin: 'js'
apply plugin: 'css'
buildscript {
    repositories {
    	jcenter()
    }
    dependencies {
       classpath 'com.eriwen:gradle-js-plugin:1.12.1'
       classpath 'com.eriwen:gradle-css-plugin:1.11.1'
    }
}

javascript.source {
	def targetDir = "$project.projectDir" + File.separatorChar + "webapp" + File.separatorChar + "resources" + File.separatorChar + "js"
    dev {
        js {
            srcDir targetDir
            include "**/*.js"
            exclude "**/*.min.js"
        }
    }
}
css.source {
	def targetDir = "$project.projectDir" + File.separatorChar + "webapp" + File.separatorChar + "resources" + File.separatorChar + "css"
    dev {
        css {
            srcDir targetDir
            include "**/*.css"
            exclude "**/*.min.css"
        }
    }
}

javascript.source.dev.js.files.eachWithIndex { jsFile, i ->
	tasks.create(name: "minifyJs${i}", type: com.eriwen.gradle.js.tasks.MinifyJsTask) {
		source 	= jsFile
		dest 	= jsFile
		//dest = jsFile.getAbsolutePath().replace('.js', '.min.js')
	}
}
task allMinifyJs(dependsOn: tasks.matching { Task task ->
		if( "$targetServer" != "local" ){
			task.name.startsWith("minifyJs")
		} else {
			println '로컬에서는 minify 하지 않음'
		}
	}
)

css.source.dev.css.files.eachWithIndex { cssFile, i ->
	tasks.create(name: "minifyCss${i}", type: com.eriwen.gradle.css.tasks.MinifyCssTask) {
		source 	= cssFile
		dest 	= cssFile
    	//dest = cssFile.getAbsolutePath().replace('.css','.min.css')
    	yuicompressor {
    		lineBreakPos = -1
    	}
    }
}
task allMinifyCss(dependsOn: tasks.matching { Task task ->
		if ( "$targetServer" != "local" ){
			task.name.startsWith("minifyCss")
		} else {
			println '로컬에서는 minify 하지 않음'
		}
	}
)



Ant

https://github.com/yui/yuicompressor

[build.xml]

	<path id="yui.classpath">
		<fileset dir="./lib">
			<include name="ant-yui-compressor-taskdef-1.0.jar" />
			<include name="yuicompressor-2.4.8.jar" />
		</fileset>
	</path>

	<taskdef resource="yuicompressor.tasks" classpathref="yui.classpath" />

	<target name="compress" description="Compress JS files using YUI Compressor">
		<!-- Compress JS files using YUI Compressor -->
		<ant-yui-compressor todir="./webapp/resources/js" deleteOriginal="false">
			<fileset dir="./webapp/resources/js">
				<include name="**/*.js" />
				<include name="**/*.min.js" />
				<exclude name="ez-common.js" />
				<exclude name="IBSheetPro3/IBSheetInfo_UTF8.js" />
			</fileset>
			<mapper type="glob" from="*.js" to="*.js" />
		</ant-yui-compressor>

		<!-- Compress CSS files using YUI Compressor -->
		<ant-yui-compressor todir="./webapp/resources/css" deleteOriginal="false">
			<fileset dir="./webapp/resources/css">
				<include name="**/*.css" />
				<include name="**/*.min.css" />
			</fileset>
			<mapper type="glob" from="*.css" to="*.css" />
		</ant-yui-compressor>
	</target>


개발/운영 환경에 따라 설정파일관련 정보들이 빌드 시점에 동적으로 변경되어야 한다.

Maven에는 Profile이라는 기능을 통하여 처리하는 반면, Gradle의 경우 System Propertie와 비슷한 방법을 이용하여 처리한다.


[디렉토리 구조]



[build.gradle]

build 시작에 properties-dev 에 있는 내용을 properties 에 옮기고, logback.xml 파일은 class root에 위치 시키는 내용이다.

build 실행 시 target이라는 옵션을 주면 된다.

-Ptarget=dev build  // 주의할 점은 java VM -D가 아니라는 점임

...

sourceSets {
	def targetServer = project.hasProperty('target') ? project.getProperty('target') : 'local'
	println "targetServer: $targetServer"
	if( "$targetServer" != "local" ){
		copy {
			from("src/main/resources/properties-$targetServer"){
				exclude 'logback.xml'
			}
			into "src/main/resources/properties"
		}
		copy {
			from("src/main/resources/properties-$targetServer"){
				include 'logback.xml'
			}
			into("src/main/resources/")
		}
		delete file("src/main/resources/properties-dev")
		delete file("src/main/resources/properties-stage")
		delete file('src/main/resources/properties-real')
	}
}

...


[build.gradle]

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'findbugs'
apply plugin: 'pmd'

repositories {
    mavenCentral()
}

sourceCompatibility = 1.7
version = '1.0'
jar {
    manifest {
        attributes 'Implementation-Title': 'StudyPd3Sample', 'Implementation-Version': version
    }
}
group = 'pe.kr.ddakker'


findbugs {
	toolVersion = "2.0.1"
	sourceSets = [sourceSets.main]
	ignoreFailures = true
	reportsDir = file("$project.buildDir/findbugsReports")
	effort = "default"
	reportLevel = "medium"
	includeFilter = file("$rootProject.projectDir/config/findbugs/includeFilter.xml")
	excludeFilter = file("$rootProject.projectDir/config/findbugs/excludeFilter.xml")
}

tasks.withType(FindBugs) {
    reports {
        xml.enabled = true
        html.enabled = false
    }
}



pmd {
	ignoreFailures = true
	toolVersion = "2.0.1"
	ruleSetFiles = files("$rootProject.projectDir/config/pmd/myRuleSet.xml")
}


dependencies {
    compile group: 'commons-collections', name: 'commons-collections', version: '3.2'
    //compile "com.google.code.findbugs:annotations:2.0.1"
    //findbugs "com.google.code.findbugs:findbugs-ant:2.0.1"
    pmd group:'pmd', name:'pmd', version:'4.2.5'
    testCompile group: 'junit', name: 'junit', version: '4.11'
}


test {
    systemProperties 'property': 'value'
}

uploadArchives {
    repositories {
       flatDir {
           dirs 'repos'
       }
    }
}

tasks.withType(Compile) {
    options.encoding = 'UTF-8'
}
/*
javadoc {
    options.addStringOption("locale","ko_KR");
    options.addStringOption("encoding","UTF-8");
    options.addStringOption("charset","UTF-8");
    options.addStringOption("docencoding","UTF-8");
}
*/


[/config/pmd/myRuleSet.xml]




    
    	
    
    
    
    
        
    
    
        
        
        
        
        
        
    


[/config/findbugs/includeFilter.xml]



	
		
	
	
		
	
	
		
	
	
		
	
	
		
	
	
		
	
	
		
	


[/config/findbugs/excludeFilter.xml]



	
		
	


+ Recent posts