인셔셔RSS 관심 있는 블로그, 뉴스, 기술 정보를 효율적으로 추적하고 읽으세요
원문 읽기 InertiaRSS에서 열기

추천 피드

博客园 - 司徒正美
V
V2EX
T
Tailwind CSS Blog
有赞技术团队
有赞技术团队
aimingoo的专栏
aimingoo的专栏
Apple Machine Learning Research
Apple Machine Learning Research
IT之家
IT之家
Blog — PlanetScale
Blog — PlanetScale
A
About on SuperTechFans
月光博客
月光博客
T
The Blog of Author Tim Ferriss
宝玉的分享
宝玉的分享
Martin Fowler
Martin Fowler
博客园 - 聂微东
The GitHub Blog
The GitHub Blog
V
Visual Studio Blog
WordPress大学
WordPress大学
酷 壳 – CoolShell
酷 壳 – CoolShell
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python)
IRIS에서 Git과 Jenkins를 사용한 지속적인 통합
InterSystems · 2026-05-24 · via DEV Community

서론

의료 통합 환경에서, InterSystems Health Connect는 생산, 비즈니스 프로세스, 운영, 서비스, 유틸리티 클래스, 루틴 및 다른 ObjectScript 아티팩트와 같은 중요한 구성 요소를 일반적으로 포함합니다. 전통적으로 이러한 구성 요소의 많은 배포는 클래스를 복사하거나 XML을 가져오거나 관리 포털의 관리 도구를 사용하여 수동으로 수행되었습니다.

이 접근 방식은 초기 단계에서는 작동할 수 있지만, 프로젝트가 커지고 여러 개발자가 병렬적으로 작업하거나 개발, 통합, 전제 생산, 생산과 같은 환경에 반복 가능한 배포가 필요할 때 유지 관리하기 어려워집니다.

더 탄력 있는 대안은 Health Connect를 지속적인 통합 내에 통합하는 것입니다. 흐름, Git을 소스 코드 저장소로 사용하고 Jenkins를 배포 오케스트레이터로 사용합니다.

이 기사의 목표는 다음을 실질적인 접근 방식으로 보여주는 것입니다.

  • GitHub에서 Health Connect 코드를 버전 관리합니다.
  • 마지막 배포 이후 변경된 파일만 감지합니다.
  • 이러한 파일을 스테이징 폴더로 복사합니다.
  • 변경 사항을 Health Connect 네임스페이스에 로드하고 컴파일합니다.
  • Jenkins을 통해 SSH를 사용하여 전체 프로세스를 원격으로 실행합니다.

아키텍처

예제로서, 다음 요소들을 구성했습니다.

건강 인스턴스용 IRIS

InterSystems IRIS for Health을 AWS 머신의 RHEL10에 배포했으며, 자체 Apache 서버를 사용하고 있으며 HTTP 및 SSH를 통해 연결을 활성화했습니다. 

개발을 위해 Visual Studio Code를 로컬 IRIS 인스턴스에서 작동하도록 구성했습니다. 여기에 코드 변경 사항을 할당한 후 GitHub에 업로드할 것입니다.


GitHub 저장소

우리는 버전 관리 시스템으로 GitHub를 선택했으며, Visual Studio Code에서 제공되는 확장 기능을 활용했습니다. 이를 통해 필요한 경우 브랜치와 함께 작업할 수 있습니다.

이 요소는 CI/CD 프로세스의 핵심 요소가 될 것입니다. 그 이유는 이곳이 배포를 위해 최신 코드를 얻을 수 있는 곳이기 때문입니다.

Jenkins

Jenkins을 아시지 않는 분들에게는, Jenkins는 개발자들이 지속적인 통합 프로세스를 위해 널리 사용하는 오픈 소스 자동화 서버입니다. 그 이유는 다양한 플러그인을 갖추고 있어 작업을 더 쉽게 만들 수 있기 때문입니다.

Jenkins에는 Groovy 스크립팅 도구가 있어서 통합 프로세스에 필요한 단계를 구현할 수 있습니다. 이 예제에서는 너무 복잡하게 하지 않겠습니다.

통합 절차

이 예제에서는 AWS 서버에 배포된 DEVELOPMENT 인스턴스와의 상호운용성 프로젝트를 진행 중이라고 가정했습니다. 여기서는 개발자들이 로컬 인스턴스에 만든 변경 사항을 테스트를 위해 배포하고자 합니다. 단계는 대략 다음과 같습니다.

  • 개발자는 로컬 인스턴스에 기능을 구현합니다.
  • 개발자는 변경 사항을 GitHub 저장소의 해당 브랜치에 업로드합니다.
  • 배포를 담당하는 사람은 Jenkins에 접속하여 파이프라인을 시작합니다.
  • Jenkins은 SSH를 통해 DEVELOPMENT 서버에 연결합니다.
  • 서버에서는 Linux 스크립트가 실행 중입니다.
  • 스크립트는 git pull을 사용하여 저장소에서 최신 변경 사항을 다운로드합니다.
  • 이 스크립트는 서버 디렉토리로 복사된 새로운 또는 수정된 파일을 식별합니다.
  • 파일이 식별되면, 스크립트는 ObjectScript에서 두 번째 스크립트를 호출합니다.
  • 두 번째 스크립트는 파일을 로드하고 컴파일하여 IRIS for Health 인스턴스에 로드합니다.
  • 업로드가 성공하면, 스크립트는 생산을 재시작합니다.

보시다시피, 우리는 매우 기본적인 작업을 선택했지만, 상당히 유용할 수 있는 작업입니다.

이제 Jenkins를 사용하여 우리의 DEVELOPMENT 서버에서 실행할 스크립트를 살펴보겠습니다.

#!/usr/bin/env bash 
set -euo pipefail

=========================

Configuration

=========================

REPO_URL="https://github.com/intersystems-ib/workshop-cicd-demo"
BRANCH="main"

Local clone used to compare commits

CACHE_REPO="/opt/git-cache/project_repo"

Folder to copy the files to be uploaded into Health Connect

EXPORT_DIR="/projectGit"

File with the latest processed commit

STATE_FILE="${CACHE_REPO}/.last_sync_commit"

CLean up EXPORT_DIR before to copy the new updates

CLEAN_EXPORT_DIR="true"

=========================

Validations

=========================

if ! command -v git >/dev/null 2>&1; then
echo "Error: git is not installed."
exit 1
fi

mkdir -p "${EXPORT_DIR}"
mkdir -p "$(dirname "${CACHE_REPO}")"

=========================

Clone or update cache folder

=========================

if [ ! -d "${CACHE_REPO}/.git" ]; then
echo "Cloning repository into cache..."
git clone --branch "${BRANCH}" "${REPO_URL}" "${CACHE_REPO}"
else
echo "Updating local cache..."
git -C "${CACHE_REPO}" fetch origin
git -C "${CACHE_REPO}" checkout "${BRANCH}"
git -C "${CACHE_REPO}" reset --hard "origin/${BRANCH}"
fi

REMOTE_COMMIT="$(git -C "${CACHE_REPO}" rev-parse HEAD)"

=========================

First execution

=========================

if [ ! -f "${STATE_FILE}" ]; then
echo "First execution."
echo "Copying all the contains from branch into ${EXPORT_DIR}..."

if [ "${CLEAN_EXPORT_DIR}" = "true" ]; then
find "${EXPORT_DIR}" -mindepth 1 -maxdepth 1 -exec rm -rf {} +
fi

rsync -av --delete --exclude ".git" "${CACHE_REPO}/" "${EXPORT_DIR}/"

echo "${REMOTE_COMMIT}" > "${STATE_FILE}"
echo "First export finished."
exit 0
fi

LAST_COMMIT="$(cat "${STATE_FILE}")"

if [ "${LAST_COMMIT}" = "${REMOTE_COMMIT}" ]; then
echo "No updates."
exit 0
fi

echo "Comparing commits:"
echo " anterior: ${LAST_COMMIT}"
echo " actual: ${REMOTE_COMMIT}"

if [ "${CLEAN_EXPORT_DIR}" = "true" ]; then
echo "Cleaning up export folder..."
find "${EXPORT_DIR}" -mindepth 1 -maxdepth 1 -exec rm -rf {} +
fi

=========================

Export just added or modified files

=========================

while IFS= read -r -d '' status && IFS= read -r -d '' path1; do
case "${status}" in
M|A)
echo "Exporting ${status}: ${path1}"
mkdir -p "${EXPORT_DIR}/$(dirname "${path1}")"
cp -f "${CACHE_REPO}/${path1}" "${EXPORT_DIR}/${path1}"
;;

D) 
  # Ignoring deletes 
  echo "Ignoring deleted: ${path1}" 
  ;; 

R*) 
  IFS= read -r -d '' path2 
  echo "Exporting renamed: ${path1} -> ${path2}" 
  mkdir -p "${EXPORT_DIR}/$(dirname "${path2}")" 
  cp -f "${CACHE_REPO}/${path2}" "${EXPORT_DIR}/${path2}" 
  ;; 

*) 
  echo "Change not automatically managed: ${status} ${path1}" 
  ;; 

esac
done < <(git -C "${CACHE_REPO}" diff --name-status -z "${LAST_COMMIT}" "${REMOTE_COMMIT}")

echo "${REMOTE_COMMIT}" > "${STATE_FILE}"
echo "Incremental export concluded in ${EXPORT_DIR}"
echo "Starting file upload and compile in Health Connect"
(echo '_system'; echo 'SYS'; cat iris.script) | iris session IRISHEALTH
echo "Compilation successfully finished"

이 스크립트는 우리의 GitHub 저장소에서 git pull을 실행하고, DEVELOPMENT 서버의 디렉토리에 소스 코드를 업데이트하고, 마지막 다운로드된 버전과 비교하여 변경 사항을 감지한 다음, 두 번째 디렉토리 (/projectGit)로 추출한 후 마지막으로 IRIS 스크립트를 호출합니다.

(echo '_system'; echo 'SYS'; cat iris.script) | iris session IRISHEALTH 

처음 두 개의 명령어는 우리가 실행해야 할 ObjectScript 스크립트를 열기 위해 필요한 터미널 세션에 사용자 이름과 비밀번호를 전달할 수 있게 해줍니다.스크립트는 우리가 수정하거나 생성한 클래스를 가져오고 컴파일하는 곳입니다. 컴파일이 성공하면, 우리의 DEMO 네임스페이스에 해당하는 생산 환경을 재시작하여 변경 사항이 적용됩니다.

zn "DEMO" 
set sc = $SYSTEM.OBJ.LoadDir("/projectGit/src/Demo", "ck", , 1)
if '$SYSTEM.Status.IsOK(sc) do $SYSTEM.Status.DisplayError(sc) quit
set production = "Demo.Order.Production"
set ^Ens.Configuration("csp","LastProduction") = production
do ##class(Ens.Director).SetAutoStart(production)
do ##class(Ens.Director).StartProduction(production)
write !,"Produccion iniciada correctamente: ",production,!

네, 우리는 스크립트, DEVELOPMENT 서버, 그리고 GitHub를 가지고 있으니 Jenkins를 설정해 보겠습니다.

Jenkins 설정

우리 파이프라인을 만들기 전에, 주요 사용자 이름과 비밀번호로 DEVELOPMENT 서버에 SSH로 연결할 수 있게 하는 플러그인을 설치해야 합니다.

Jenkins 설정에서 우리는 DEVELOPMENT 서버에 대한 접근 자격 증명을 만들었습니다:

그리고 마지막으로 파이프라인을 생성합니다.

파이프라인 구성에서 다음 스크립트를 정의하여 배포를 가능하게 합니다.

pipeline {
agent any
parameters {
    string(name: 'GIT_BRANCH', defaultValue: 'main', description: 'Repository branch')
    string(name: 'REMOTE_HOST', defaultValue: 'ec2-**-**-***-**.**-*****.compute.amazonaws.com', description: 'Remote Host')
    string(name: 'REMOTE_USER', defaultValue: 'ec2-user', description: 'Remote SSH user')
    string(name: 'REMOTE_SCRIPT_NAME', defaultValue: 'shell_script.sh', description: 'Remote script name')
}

environment {
    REPO_URL = 'https://github.com/intersystems-ib/workshop-cicd-demo'
    SSH_CREDENTIALS_ID = 'ssh-healthconnect-remote'
}

stages {
    stage('Checkout') {
        steps {
            git branch: "${params.GIT_BRANCH}", url: "${env.REPO_URL}"
        }
    }

    stage('Validate script') {
        steps {
            sh '''
                set -eu
                test -f shell_script.sh
                chmod +x shell_script.sh
            '''
        }
    }

    stage('Launch remote script') {
        steps {
            sshagent(credentials: ["${env.SSH_CREDENTIALS_ID}"]) {
                sh '''
                    set -eu

                    ssh -o StrictHostKeyChecking=no "${REMOTE_USER}@${REMOTE_HOST}" \
                      "sudo sh '/${REMOTE_SCRIPT_NAME}'" | tee remote_execution.log
                '''
            }
        }
    }
}

post {
    always {
        archiveArtifacts artifacts: 'remote_execution.log', allowEmptyArchive: true
    }
    success {
        echo 'Remote deployment successfully finished.'
    }
    failure {
        echo 'Remote deployment failed. Check remote_execution.log.'
    }
}

}

우리의 스크립트는 무엇을 합니까? 매우 간단합니다. GitHub 저장소가 존재하고 관련 브랜치가 있는지 확인한 다음, SSH를 통해 Linux 스크립트를 실행하는 지시를 보냅니다. 해당 스크립트는 인스턴스를 다운로드하고 업데이트하는 역할을 합니다.

작은 예제를 통해 실제 동작을 보겠습니다.

프로세스를 실행합니다.

우리의 생산은 정상적으로 진행 중이며, 하나의 구성 요소를 변경하여 하나의 매개변수에서 표시되는 기본값이 다르게 만들고자 합니다.

이제 우리의 TenantId 매개변수에 값 ZZZ-999을 가지도록 하자, 멋지네, 우리가 로컬 인스턴스의 Visual Studio Code에 있는 코드를 수정하고 변경 사항을 GitHub에 업로드하자.

변경 사항이 리포지토리에 푸시되었으니, 우리 Jenkins 인스턴스에서 파이프라인을 실행할 수 있습니다. 파이프라인의 출력을 확인해 보겠습니다.

모든 것이 올바릅니다; 변경 사항을 감지하고 스크립트를 성공적으로 실행했습니다.

파라미터가 변경되었는지 확인하고 생산이 성공적으로 재시작되었는지 확인해 보겠습니다.

이제 새로운 TenantId를 가지게 되었습니다! 완벽하고 훌륭한 성공입니다.

결론 및 다음 단계.

IRIS에서 기술적 제약 없이 지속적인 통합 프로세스에 참여할 수 있음을 알 수 있을 것입니다. 당신의 일상적인 운영에 가장 적합한 스크립트만 필요합니다.

이 기사에서 우리는 건강을 위한 IRIS와의 지속적인 통합의 작은 예를 보았지만, 이는 Configuration Merge와 같은 기능을 사용하여 배포될 수 있는 특정 구성으로 확장될 수 있습니다.

시도해보세요!