CI/CD
Automating the Build and Deploy Pipeline
I replaced a fully manual dev-server deploy — build, transfer, restart, all done by hand — with a Jenkins pipeline. Push to GitLab and the build-and-deploy runs on its own.
- Deploy time
- 20 min → 4 min
- Automation scope
- 3 stages
- Trigger
- GitLab Webhook
- Infrastructure
- Docker + Jenkins
~80% reduction
Checkout · Build · Deploy
Branch-based auto-detection
Declarative Pipeline
Problem
15–20 minutes per deploy, zero traceability
Dev-server deployments were entirely manual — build, transfer, restart, all done by hand. A single deploy took 15–20 minutes, during which other developers were stuck waiting, and there was no record anywhere of who deployed what and when. With frequent deploys, a mistyped command or a wrong-environment slip would creep in from time to time, and each one added a rollback-and-redeploy overhead on top.
15–20 min per deploy on average
Build, transfer, and restart all run manually in sequence
No way to trace deploy history
No record of who deployed what and when
Blocking wait time
Other work would stall while a deploy was in progress
Human errors during manual work
Typos or wrong-environment mix-ups occasionally caused incidents
Approach
A CI/CD pipeline built on Jenkins
Using a Jenkins Declarative Pipeline, I defined the whole build-and-deploy procedure in a single Jenkinsfile. A GitLab Webhook detects pushes to a specific branch, and the Checkout → Build → Deploy stages run in sequence.
Trigger
Developer
git push devtest
GitLab
Webhook dispatch
Jenkins Pipeline
Checkout
git clone
Build
mvn clean package
Deploy
SSH + deploy.sh
Target
Staging Server
WAR deploy + WAS restart
Average time per deploy
min
Before · manual
15 – 20 min
After · automated
4 min
▼ ~80% reduction
Process
Implementation steps
- 01
Run Jenkins in a Docker container
To avoid messing up the host environment, I ran Jenkins inside a Docker container. Jobs, plugins, and credentials were split out to volumes, so the configuration survives restarts intact.
- 02
Connect the GitLab Webhook
Push events from the GitLab repository are forwarded to Jenkins, and a
regexpFilterExpressionfilters them so the build only runs for pushes to the devtest branch. - 03
Write the Jenkinsfile
I split the pipeline into Checkout → Build → Deploy stages, so if something fails it is immediately obvious which stage stopped. Deploy ships the WAR file over SSH and then runs the server-side
deploy.shto handle the WAS restart — all in one go.Jenkinsfilegroovy// Jenkins Declarative Pipeline - GitLab Webhook 연동 자동 배포pipeline {agent anytriggers {GenericTrigger(genericVariables: [[key: 'BRANCH_NAME', value: '$.ref'],[key: 'EVENT_TYPE', value: '$.event_name']],regexpFilterExpression: '^refs/heads/devtest push$')}stages {stage('Checkout') {steps {git branch: 'devtest',credentialsId: 'gitlab-ssh-key',url: 'ssh://git@server/gitlab/goad.git'}}stage('Build') {steps {sh 'mvn clean package -P staging'}}stage('Deploy') {steps {sshPublisher(publishers: [sshPublisherDesc(configName: 'staging-server',transfers: [sshTransfer(sourceFiles: 'target/issga.war',execCommand: '/home/deploy/deploy.sh')])])}}}} - 04
Surface build status on GitLab commits
Build results are reported back as GitLab commit statuses, so when you look at a commit in GitLab you can immediately see whether the build succeeded, failed, or is still running.
Outcome
Results and takeaways
Deploy time: 20 min → 4 min
Work that used to take 15–20 minutes manually dropped to around 4 minutes with the automated pipeline.
Manual mistakes disappeared
The kinds of errors that came from manual steps — command typos, wrong-environment mix-ups — are now virtually gone.
No more blocking wait time
Once a push goes out, developers can move straight on to the next task while the pipeline runs.
Pipeline beat Freestyle
I first tried a Freestyle Job, but Pipeline turned out to be far better for traceability, reuse, and extensibility. It really drove home why capturing the procedure as code matters.
MORE
Explore other cases
Badabom
AUTH / SSO
Building an SSO Provider for Partner Sites
Implemented an SSO Provider so external partner sites (e.g., OTT) could sign in with Badabom accounts. Single-use UUID tokens stored in the database support multiple WAS nodes, and CI (Connecting Information) auto-maps accounts across both sides.
View detailBadabom
DEVOPS / OBSERVABILITY
SSE + Cross-WAS Real-Time Log Viewer
The WAS lived in the Daejeon IDC, but network-segregation policy meant only Busan-office PCs could reach it — so pulling a log effectively meant flying to Busan. I built an SSE-based viewer inside the admin web and added a cross-WAS relay so logs from both WAS nodes stream into a single screen.
View detailBadabom
LEGACY MIGRATION
Migrating the OTT Technology-Trade System into Badabom
Moved an Oracle + MyBatis technology-trade platform (OTT) onto PostgreSQL + iBATIS. Rewrote 87 URLs, 34 JSPs, 80+ SQL queries, and 14 tables.
View detailGAIS — Government Advertising Integrated Support System
INFRA / SESSION
Redis-Backed Session Clustering
JEUS Standard doesn't support native session clustering, so I put Redis in front as an external session store. That unlocked rolling restarts across WAS nodes.
View detailGAIS — Government Advertising Integrated Support System
SECURITY / NETWORK
Applying TLS 1.3 via an Nginx Reverse Proxy
Touching the shared WebtoB SSL felt risky, so I put Nginx in front and terminated TLS there instead. Existing services kept running untouched while TLS 1.3 was rolled out.
View detailFreelance · Side Projects
CLIENT WORK / WEB
Pitched and Built a Postpartum Care Center Site Renewal
My wife had stayed at a postpartum care center whose website felt dated, so I mocked up a UI sample and pitched it myself. I built an Astro static site with a 192-frame scroll animation, Kakao Map, and SEO — then shipped it to their production domain.
View detailFreelance · Side Projects
SIDE PROJECT / AI
Family-Driven Baby Naming with AI + Tournament-Style Voting
Existing naming services are designed for solo use, so I built a way for the whole family to join in. GPT-4o suggests names aligned with Saju (birth-chart) and Ohaeng (Five-Element) rules, and the family votes tournament-style to pick the final name.
View detail