15์ฅ ๋ณด์ ์๊ฒฉ ์ ๊ทผ ๋ฐ CI/CD๋ฅผ ์ํ ๋์ปค ์ค์
๋์ปค ์์ง๊ณผ API ๋ถ๋ฆฌ์ ์ปจํ ์ด๋ ๋๊ตฌ์ ์ ํ์ง๊ฐ ๋์ด์ง๊ณ , ๋ก์ปฌ ๋ช ๋ นํ ๋๊ตฌ๋ก๋ ์๊ฒฉ ์ปดํจํฐ์์ ์คํ์ค์ธ ๋์ปค ์์ง ๊ด๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋ค.
15.1 ๋์ปค API์ ์๋ํฌ์ธํธ ํํ
- ๋์ปค ์์ง์ ์๊ฒฉ์์ ์ ๊ทผํ ์ ์๊ฒ ํ๋ ค๋ฉด ๋ช ์์ ์ผ๋ก ์ธ๋ถ ์ ๊ทผ์ ํ์ฉํด์ผ ํ๋ค.
- HTTP ๋ก ์ ๊ทผ์ ํ์ฉํ๋ ๊ฒฝ์ฐ๋ ๋ฐ๋์ ํผํด์ผ ํ๋ค.
- ๋์ปค ์์ง์ด HTTP๋ก ์ ๊ทผ ๊ฐ๋ฅํ๊ฒ ์ค์ ๋ ๊ฒฝ์ฐ ํธ์คํธ ์ฃผ์๋ง ์๋ฉด ๋๊ตฌ๋ ์ง ๋์ปค ์์ง์ ๋ง์๋๋ก ์ฌ์ฉํ ์ ์๋ค.
15.2 ๋ณด์ ์๊ฒฉ ์ ๊ทผ์ ์ํ ๋์ปค ์์ง ์ค์
๋์ปค์๋ API ์์ฒญ์ ๋ฐ์ ์ ์๋ ์ฑ๋์ด ๋ ๊ฐ์ง๊ฐ ์๋ค.
A. ์ ์ก ๊ณ์ธต ๋ณด์ (TLS)
- ๋์ปค API ๋ ์ํธ TLS๋ฅผ ์ฌ์ฉํ์ฌ ์๋ฒ์ ํด๋ผ์ด์ธํธ๊ฐ ๊ฐ๊ฐ ์ธ์ฆ์๋ฅผ ๊ฐ์ง๋ค.
- ์๋ฒ์ ์ธ์ฆ์๋ ์์ ์ ์ฆ๋ช ํ๊ณ ์ ์ก์ ์ํธํ ํ๋ฉฐ, ํด๋ผ์ด์ธํธ๋ ์์ ์ ์ฆ๋ช ํ๋๋ฐ ์ฌ์ฉํ๋ค.
- TLS ๋ ๋ง์ด ์ฌ์ฉ๋๋ ๋ฐฉ๋ฒ์ด์ง๋ง, ์ธ์ฆ์ ์์ฑ, ๊ต์ฒด ๋ฑ์ ๊ด๋ฆฌ ์ค๋ฒํค๋๊ฐ ๋ฐ์ํ๋ค.
B. ๋ณด์ ์ ธ (SSH)
- SSH ๋ ๋ฆฌ๋ ์ค ์๋ฒ์์ ์๊ฒฉ ์ ์ํ๋ ํ์ค ํ๋กํ ์ฝ์ด๋ค.
- SSH ๋ ํด๋ผ์ด์ธํธ์ ๋ํ ์๊ฒฉ ์ ๊ทผ ๊ถํ๊ด๋ฆฌ๊ฐ ์๋์ ์ผ๋ก ์ฝ๋ค.
์ํธ TLS๋ฅผ ์ด์ฉํด ๋์ปค ์์ง์ ๋ณด์ ์๊ฒฉ ์ ๊ทผ ์ค์ ํ๊ธฐ
A. ์ธ์ฆ์์ ํค ํ์ผ ์์ ๋๊ฐ ๋ง๋ ๋ค.
B. ์ธ์ฆ์๋ฅผ ๋ฐฐํฌํ ์ปจํ ์ด๋๋ฅผ ์คํํ๋ค.
C. ๋ ๊ฐ์ ๋ณผ๋ฅจ์ด ๋ง์ดํธ ๋๋ค.
D .์ปจํ ์ด๋๊ฐ ๊ฐ๊ณ ์๋ ์ธ์ฆ์์ daemon.json ํ์ผ์ ๋ ธ๋๋ก ๋ณต์ฌํ๋ค.
$ mkdir diamol-certs
# ca key ์ ์์ฑ
$ openssl genrsa -out ca.key 2048
$ openssl req -x509 -new -nodes -key ca.key -days 365 -out ca.crt
# ์ธ์ฆ์ ์์ฑ
$ openssl req -newkey rsa:2048 -nodes -keyout server.key -out server.csr
$ openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -out server.crt -day 365
$ docker container run -v /diamol-certs:/certs -v /etc/docker:/docker diamol/pwd-tls:server
$ vi /etc/docker/daemon.json
{
"hosts": ["unix://var/run/docker.sock", "tcp://0.0.0.0:2376"],
"tls": true,
"tlscacert": "/diamol-certs/ca.pem",
"tlskey": "/diamol-certs/server-key.pem",
"tlscert": "/diamol-certs/server-cert.pem"
}
$ sudo systemctl restart docker
๋ณด์ ์ ธ (SSH)
- SSH ์ ์ฅ์ ์ ๋์ปค CLI๊ฐ ํ์ค SSH ํด๋ผ์ด์ธํธ๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ๋์ปค ์์ง ์ชฝ์์ ์ค์ ์ ๋ณ๊ฒฝํ ํ์๊ฐ ์๋ค.
- ์ฌ์ฉ์ ์ธ์ฆ์ ์๋ฒ๊ฐ ๋์ ์ฒ๋ฆฌ, ์ธ์ฆ์๋ฅผ ์์ฑํ ํ์๊ฐ ์๋ค.
- ํธ์คํธ์์ ์๊ฒฉ ์ ์์ ์ฌ์ฉํ ๊ณ์ ์ ์ถ๊ฐํ๊ธฐ๋ง ํ๋ฉด ๋.
15.3 ๋์ปค ์ปจํ ์คํธ๋ฅผ ์ฌ์ฉํด ์๊ฒฉ ์์ง์์ ์์ ํ๊ธฐ
- ๋์ปค ์ปจํ ์คํธ๋ฅผ ์ฌ์ฉํ๋ฉด ์๊ฒฉ์ผ๋ก ์ ๊ทผํ ๋์ปค ์์ง์ ํธ๋ฆฌํ๊ฒ ์ ํํ ์ ์๋ค.
- ๋์ปค ์ปจํ ์คํธ๋ ๋์ปค CLI ์์ ์๊ฒฉ ์ ๊ทผ์ ํ์ํ ๋ชจ๋ ์์ธ ์ ๋ณด๋ฅผ ์ง์ ํ๋ฉด ์์ฑํ ์ ์๋ค.
$ docker context create pwd-tls --docker "host=tcp://$pwdDomain, ca=/tmp/pwd-certs/ca.pem, cert=/tmp/pwd-certs/client-cert.pem, key=/tmp/pwd-certs/client-key.pem"
$ docker context create local-tls --docker "host=ssh://user@server"
$ docker context ls
$ docker context use pwd-tls
- ์ปจํ ์คํธ์๋ ์๊ฒฉ Docker ์์ง ๊ฐ์ ๋์์ ์ ํํ๊ธฐ ์ํด ํ์ํ ์ ๋ณด (์๋ํฌ์ธํธ, ์ธ์ฆ์ ๋ฑ)์ด ํฌํจ๋๋ค.
- ์ปจํ ์คํธ๋ ํ ๋ฒ ์์ฑ๋๋ฉด ์๊ตฌ์ ์ผ๋ก ์ ์ฅ๋๋ฉฐ, ์๋ก์ด ํฐ๋ฏธ๋ ์ธ์ ์์๋ ์ฌ์ฉํ ์ ์๋ค.
- ๊ทธ๋ฌ๋, ํน์ ์ปจํ ์คํธ๋ฅผ ํ์ฑํํ ์ํ๋ ํฐ๋ฏธ๋ ์ธ์ ๋ง๋ค ๊ฐ๋ณ์ ์ด๋ค.
- ๋ง์ฝ, ํด๋น ์ค์ ์ ๋ค๋ฅธ ํฐ๋ฏธ๋ ์ธ์ ์๋ ๋ชจ๋ ์๊ตฌ์ ์ผ๋ก ์ค์ ํ๊ณ ์ถ์ผ๋ฉด ๊ธฐ๋ณธ๊ฐ ํ๊ฒฝ๋ณ์๋ก ์ง์ ํ๋ฉด ๋๋ค.
$ export DOCKER_CONTEXT='pwd-tls'
15.4 ์ง์์ ํตํฉ ํ์ดํ๋ผ์ธ์ ์ง์์ ๋ฐฐํฌ ์ถ๊ฐํ๊ธฐ
- ์ธ์ฆ ์๋จ์ ์ ๋๋ก ํ์ ๊ด๋ฆฌ ๋๊ตฌ์ ์ ์ฅํ์ง ์๋๋ค.
- ์๋ํ ์๋ฒ๋ ๋น๋ฐ๊ฐ์ ๋น๋ ์๋ฒ ๋ด๋ถ์ ์์ ํ๊ฒ ๋ณด๊ดํ๊ณ , ํ์ดํ๋ผ์ธ ์์ ์ ํ์ฉํ๋ค.
- CI/CD ํ์ดํ๋ผ์ธ์ Docker ๋ฐ Docker Compose ๋ช ๋ น์ด๋ฅผ ์ญํ ์ ๋ง๊ฒ ์ฌ์ฉํด ๋ณต์ก์ฑ์ ์ค์ด๊ณ ํจ์จ์ฑ์ ๋์ฌ์ผ ํ๋ค.
$ vi Jenkinsfile
pipeline {
agent any
environment {
REGISTRY = "registry.local:5000"
UAT_ENGINE = "ip172-18-0-69-bthrciiosm4g00b8b730-2376.direct.labs.play-with-docker.com:80"
PROD_ENGINE = "ip172-18-0-69-bthrciiosm4g00b8b730-2376.direct.labs.play-with-docker.com:80"
}
stages {
stage('Verify') {
steps {
dir('ch15/exercises') {
sh 'chmod +x ./ci/00-verify.bat'
sh './ci/00-verify.bat'
}
}
}
stage('Build') {
steps {
dir('ch15/exercises') {
sh 'chmod +x ./ci/01-build.bat'
sh './ci/01-build.bat'
}
}
}
stage('Test') {
steps {
dir('ch15/exercises') {
sh 'chmod +x ./ci/02-test.bat'
sh './ci/02-test.bat'
}
}
}
stage('Push') {
steps {
dir('ch15/exercises') {
sh 'chmod +x ./ci/03-push.bat'
sh './ci/03-push.bat'
echo "Pushed web to <http://$REGISTRY/v2/diamol/ch15-timecheck/tags/list>"
}
}
}
stage('UAT') {
steps {
withCredentials([file(credentialsId: 'docker-ca.pem', variable: 'ca'),
file(credentialsId: 'docker-cert.pem', variable: 'cert'),
file(credentialsId: 'docker-key.pem', variable: 'key')]) {
dir('ch15/exercises') {
sh 'chmod +x ./ci/04-uat.bat'
sh './ci/04-uat.bat'
echo "Deployed to UAT"
}
}
}
}
stage('Await approval') {
steps {
input message: 'Deploy to prod?', ok: 'Do it!'
}
}
stage('Production') {
steps {
withCredentials([file(credentialsId: 'docker-ca.pem', variable: 'ca'),
file(credentialsId: 'docker-cert.pem', variable: 'cert'),
file(credentialsId: 'docker-key.pem', variable: 'key')]) {
dir('ch15/exercises') {
sh 'chmod +x ./ci/05-deploy.bat'
sh './ci/05-deploy.bat'
echo "Deployed to PROD"
}
}
}
}
}
}
$ vi ./ci/00-verify.bat
docker version && docker-compose version
$ vi ./ci/01-build.bat
docker-compose -f docker-compose.yml -f docker-compose-build.yml build --pull
$ vi ./ci/02-test.bat
docker-compose up -d && docker-compose ps && docker-compose down
$ vi ./ci/03-push.bat
docker-compose -f docker-compose.yml -f docker-compose-build.yml push
$ vi ./ci/04-uat.bat
docker-compose --host tcp://$UAT_ENGINE --tlsverify --tlscacert $ca --tlscert $cert --tlskey $key -p timecheck-uat -f docker-compose.yml -f docker-compose-uat.yml up -d
$ vi ./ci/05-deploy.bat
docker-compose --host tcp://$PROD_ENGINE --tlsverify --tlscacert $ca --tlscert $cert --tlskey $key -p timecheck-prod -f docker-compose.yml -f docker-compose-prod.yml up -d
A. ๊ฒ์ฆ ๋จ๊ณ
B. ๋น๋ ๋จ๊ณ
C. ํ ์คํธ ๋จ๊ณ
D. ์๊ฒฉ ๋์ปค ๊ฐ๋ฐ๊ธฐ ๋ฐฐํฌ
F. ์๊ฒฉ ๋์ปค ์ด์๊ธฐ ๋ฐฐํฌ
15.5 ๋์ปค ๋ฆฌ์์ค์ ์ ๊ทผ ๋ชจ๋ธ
๋์ปค ์์ง์ ๋ณด์์ ๋ ๊ฐ์ง๊ฐ ์๋ค.
- ๋ช ๋ นํ ๋๊ตฌ์ API ์ฌ์ด์ ํต์ ์ ์ํธํ
- ํ๊ฐ๋ฐ์ ์ฌ์ฉ์๋ง API ์ ๊ทผ ํ์ฉ
๊ถํ์ ์กฐ์ ํ ์ ์๋ ๊ธฐ๋ฅ์ ์๋ค.
๋ชจ๋ ๊ฒ์ ํ ์ ์๊ฑฐ๋, ์๋ฌด๊ฒ๋ ํ ์์๋ ๊ฒ ๋ ์ค ํ๋๋ค.
์ฟ ๋ฒ๋คํฐ์ค์๋ ์ญํ ๊ธฐ๋ฐ ์ ๊ทผ ์ ์ด ๋ชจ๋ธ์ ์ฌ์ฉํ๋ค.
์ด๋ฅผ ํตํด ์ฌ์ฉ์ ์ ๊ทผ, ๋ฆฌ์์ค ์ ์ด ๋ฑ์ ์ธ์ธํ ์ปจํธ๋กค ํ ์ ์๋ค.