Run The Bridge
docker-registry를 이용해 toyproject k8s에 deployment로 올리기 본문
0. 실습과제
1. Private docker-registry를 k8s의 RelicaSet으로 올리기
해당 작업을 하기 위해서는 먼저 docker-registry를 올려야 한다.
docker-registry를 올릴 때, NFS를 사용하기 때문에 pv, pvc 설정도 해주어야 하며, registry의 config.yml 파일의 위치도 지정해주어야 한다.
docker-registry.yaml 파일 구조는 다음과같다.
# vi docker-registry.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: docker-registry
labels:
app: docker-registry
spec:
replicas: 1 # replicas 설정
selector:
matchLabels:
app: docker-registry # template 이름과 맞춰준다.
template:
metadata:
name: docker-registry
labels:
app: docker-registry # 임의설정
spec:
containers:
- name: docker-registry # pod 이름지정
image: registry:2.6 # image 버전
volumeMounts: # NFS mount 지점 설정
- name: docker-config-yml
mountPath: /etc/docker/registry # 마운트포인트
- name: nfs-volume
mountPath: /mnt # NFS 파일공유 위치
ports:
- containerPort: 5000 # 사용할 port
volumes:
- name: docker-config-yml
configMap:
name: config-envfile # config.yml를 configMap으로 만든다음 설정
- name: nfs-volume
persistentVolumeClaim: # NFS 사용을 위한 pv, pvc 설정
claimName: docker-registry-pvc
docker-registry에 들어가는 config.yml 파일의 구조는 다음과 같다. filesystem의 rootdirectory만 '/mnt'로 바꿔주었다.
# vi config.yml
version: 0.1
log:
level: info
storage:
filesystem:
rootdirectory: /mnt
delete:
enabled: true
http:
addr: 0.0.0.0:5000
NFS 연결을 위한 pv 파일 구조는 다음과같다.
# vi docker-registry-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: docker-registry-pv # 임의의 이름
spec:
capacity:
storage: 5Gi # 5gb
accessModes:
- ReadWriteMany
volumeMode: Filesystem
persistentVolumeReclaimPolicy: Retain
nfs:
server: 192.168.100.140 # NFS, master Node의 IP
path: /nfs/images # /nfs에 images 디렉토리를 생성하고 경로를 잡는다.
pv를 보았으니 이제 pvc도 필요하므로 pvc 구조는 다음과같다.
# vi docker-registry-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: docker-registry-pvc # 임의이름
spec:
storageClassName: ""
accessModes:
- ReadWriteMany # 1:N
resources:
requests:
storage: 5Gi # 5GB
또한 실습과제에서 NodePort로 노출해야 하므로 NodePort.yaml 파일도 짜야한다. 다음과 같다
# vi docker-registry-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: docker-registry-nodeport
spec:
ports:
- name: docker-registry-nodeport
port: 5000 # 외부 통신 포트
targetPort: 5000 # 내부 통신 포트
nodePort: 30000 # 노출할 NodePort
selector:
app: docker-registry # docker-registry.yaml에 정의한 이름
type: NodePort
여기까지 하면 registry 설정은 끝난다. 이제 마지막인 'myregistry.images.io:30000'로 접속 부분을 해결해야 한다.
예전에도 한 번 설명했는데 /etc/hosts 와 /etc/docker/daemon.json 파일을 건드려줘야 한다.
한 번 해보자.
# vi /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.100.140 kube-master1
192.168.100.140 myregistry.images.io
192.168.100.141 kube-worker1
192.168.100.142 kube-worker2
# vi /etc/docker/daemon.json
{
"insecure-registries": ["192.168.100.140:5000", "myregistry.images.io:30000"]
}
위의 세팅을 3개의 Node 전부 다 해줘야 한다.
윈도의 DNS 설정이라고 보면 된다.
C:\Windows\System32\drivers\etc\hosts
위의 경로에 위치한 hosts 파일과 똑같다 보면 된다.
위의 설정이 전부 끝났다면 'kubectl apply -f'으로 yaml파일을 모두 실행시켜주자
모두 잘 올라왔다.
우리가 수정한 대로 yml 파일이 잘 들어갔다. mkdir || touch를 사용해서 아무 파일이나 만든 뒤, /nfs/images에서 확인
test 디렉터리가 잘 만들어진다. 이제 image를 Pull 하면 /nfs/images로 저장되게 하면 된다.
2. toyproject에 작성한 app을 k8s에 Deployment로 올리기
2-1 mariadb01
예전에 사용한 파일들을 '.yaml'파일로 고쳐야한다.
천천히 Database 먼저 구축해보자. 먼저 mariadb01부터 한다
요구조건
- replicas 1
- Cluster IP type
- app간 호출은 service name
- db의 데이터 NFS를 이용하여 PV를 사용
그리고 하기전에 imaeg를 먼저 아까만든 /nfs/images에 mount 시켜놓고, yaml파일로 불러와야 한다.
(공개망이면 docker hub를 쓰면되지만, 폐쇄망이면 private-registry를 사용해야하기 때문)
# vi Dockerfile_mariaDB_01
FROM mariadb:10.6.3
ENV MYSQL_ROOT_PASSWORD=root
ENV MYSQL_DATABASE=flask01_db
ENV MYSQL_USER=flask01
ENV MYSQL_PASSWORD=flask01
COPY my.cnf /etc/mysql/my.cnf
EXPOSE 3000
CMD ["mysqld"]
docker build -t mariadb01:0.0 -f Dockerfile_mariaDB_01 # build
docker images # build 확인
docker tag mariadb01:0.0 myregistry.images.io:30000/mariadb01:0.0 # tag명 변경
docker images # 결과 확인
--------------------------result--------------------------
myregistry.images.io:30000/mariadb01 0.0 52b730d4f0e9 About a minute ago 409MB
--------------------------result--------------------------
docker push myregistry.images.io:30000/mariadb01:0.0 # /nfs/images로 push
mariadb01이 push된 것을 볼 수 있다.
이제 push가 되었으니 .yaml 파일을 만들어야 한다.
# vi mariadb01.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mariadb01
labels:
app: mariadb01
spec:
replicas: 1
selector:
matchLabels:
app: mariadb01
template:
metadata:
name: mariadb01
labels:
app: mariadb01
spec:
containers:
- name: mariadb01
image: myregistry.images.io:30000/mariadb01:0.0 # push된 image를 받는다.
volumeMounts:
- name: maraidb01-database
mountPath: /var/lib/mysql # my.cnf 저장
ports:
- containerPort: 3000
volumes:
- name: maraidb01-database # DB data를 위해 volume 사용
persistentVolumeClaim:
claimName: mariadb01-pvc
다음은 포트를 열어주어야 한다.
# vi mariadb01-clusterIP.yaml
apiVersion: v1
kind: Service
metadata:
name: mariadb01-clusterip
spec:
ports:
- name: mariadb01-clusterip
port: 3000
targetPort: 3000
selector:
app: mariadb01
type: ClusterIP
이제 pv, pvc 설정만 하면 DB-01은 완료
# vi mariadb01-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: mariadb01-pvc
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteMany
volumeMode: Filesystem
persistentVolumeReclaimPolicy: Retain
nfs:
server: 192.168.100.140
path: /nfs/mariadb_database
# vi mariadb01-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mariadb01-pvc
spec:
storageClassName: ""
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi
모든 파일을 작성완료했으면 'kubectl apply -f'로 실행시켜준다.
DB에 데이터를 간단하게 만들고, '/nfs'에 가서 확인한다.
registry에 mariadb 자료가 잘 들어와있다.
같은방법으로 mariadb02도 해주면된다.
2. toyproject에 작성한 app을 k8s에 Deployment로 올리기
2-2 flask01
flask도 크게 차이점은 없다. 오히려 pv, pvc를 사용하지 않기 때문에 간단하다. 빠르게 알아보자
요구조건
- relicas 1
- ClusterIP type
- app간 호출은 service name
flask01도 image를 push 해야하는건 똑같다.
# vi Dockerfile_python_01
FROM python:3
WORKDIR /usr/src/app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install pymysql
COPY . .
EXPOSE 8000
CMD ["python", "./app.py"]
# vi requirements.txt
flask==2.0.1
pymysql
requests==2.25.1
urllib3==1.26.4
xmltodict==0.12.0
docker build -t myregistry.images.io:30000/flask01:0.0 -f Dockerfile_python_01 . # tag명을 변경하지않고 바로 진행
docker images # image 확인
docker push myregistry.images.io:30000/flask01:0.0 # /nfs/images로 push
이제 .yaml파일만 작성하면 된다.
# vi flask01.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: flask01
labels:
app: flask01
spec:
replicas: 1
selector:
matchLabels:
app: flask01
template:
metadata:
name: flask01
labels:
app: flask01
spec:
containers:
- name: flask01
image: myregistry.images.io:30000/flask01:0.0
imagePullPolicy: Always # app.py에 변동이 있으면 rebuild
ports:
- containerPort: 8000
# vi flask01-clusterIP.yaml
apiVersion: v1
kind: Service
metadata:
name: flask01-clusterip
spec:
ports:
- name: flask01-clusterip
port: 8000
targetPort: 8000
selector:
app: flask01
type: ClusterIP
# vi app.py
import pymysql
import time
from flask import Flask
time.sleep(5)
app = Flask(__name__)
@app.route("/select", methods=["GET"])
def select():
juso_db = pymysql.connect(
user='flask01',
password='flask01',
host='mariadb01-clusterip', # mariadb01의 service pod에서 설정한 이름: mariadb01-clusterip
port=3000,
db='flask01_db',
charset='utf8'
)
cursor = juso_db.cursor()
sql = "select id, email, phone_number from private;"
cursor.execute(sql)
row = cursor.fetchall()
print(row)
lst = []
for data in row:
dic = {
'id' : data[0],
'email' : data[1],
'phone_number' : data[2]
}
lst.append(dic)
juso_db.close()
return str(lst)
@app.route('/')
def hello_world():
return 'Hello, world!'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000)
모든 파일을 작성했으면 'kubectl apply -f'로 실행시킨다.
그다음에 service 명을 보고 curl를 날려서 flask01이 잘 받아오는지 확인한다. (나는 성공)
똑같은 방식으로 flask02도 올리면된다.
app.py 내용만 조금 바뀐다.
2. toyproject에 작성한 app을 k8s에 Deployment로 올리기
2-3 main
main은 이제 외부접속이 가능해야하므로 NodePort를 사용한다.
요구조건
- replicas 1
- NodePort type
- app간 호출은 service name
main도 마찬가지로 /nfs/images에 push 해놓고 받아야한다.
# vi Dockerfile_main
FROM python:3
WORKDIR /usr/src/app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install pymysql
COPY . .
EXPOSE 8000
CMD ["python", "./app_main.py"]
docker build -t myregistry.images.io:30000/main -f Dockerfile_main . # tag명을 바로 지정
docekr images # 확인
docker push myregistry.images.io:30000/main:latest # /nfs/images로 push
이제 yaml파일을 작성한다.
# vi main.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: main
labels:
app: main
spec:
replicas: 1
selector:
matchLabels:
app: main
template:
metadata:
name: main
labels:
app: main
spec:
containers:
- name: main
image: myregistry.images.io:30000/main:0.0 # push 해논 image를 pull
imagePullPolicy: Always
ports:
- containerPort: 8000
# vi main-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: main-nodeport
spec:
ports:
- name: main
port: 8000 # 외부통신포트
targetPort: 8000 # 내부통신포트
selector:
app: main
type: NodePort
모든 yaml 파일 작성이 끝나면 이제 'kubectl apply -f'로 실행한다.
service가 올라갔으므로 외부접속을 통해 확인해본다.
master node의 IP를 적어준다.
위와같이 뜨면 성공!
N. 소감
어려웠던 점: pv, pvc를 직전에 배우고 바로 실습에 들어가서 응용부분에 어려움을 느꼈다. 또한 예전엔 docker-compose.yml 파일을 썼다면, 지금은 파일마다 .yaml 파을 만들어줘야해서 헷갈리지않게 생각해야 했다. 또한 port에 대해서 내부통신포트와 외부통신포트를 어떻게 지정해주어야 하는지 확신이 없었다. 마지막으로 private-registry를 사용해서 push해야해서 이때까지 해오던 실습방식과 좀 달랐다.
해결방안: pv, pvc는 강의시간에 사용한 파일을 사용해 test를 진행해서 동작하는것을 확인하였으며, .yaml파일도 양식이 크게 다르지 않았다. private-registry는 생각보다 금방 구현이 되었다. 이또한 ubuntu:16.04 버전으로 test를 통해 image가 올라가는것을 확인했으며, port는 강사님 도움을 받아 하나의 port를 써도된다고 하셨다. (why? → Pod마다 IP가 다르기 떄문에)
느낀 점: 이떄까지 사용하던 모든 실습들의 집약체라고 느껴졌다. 모든걸 다 이해하고있어야 고민하면서 파일을 작성할 수 있었고, 혼자했다면 '이게 맞나?, 아닌가?' 하면서 수없이 고민했을것이다. 그래도 꾸준히 블로그에 리뷰같은 복습을 하면서 내용을 익혀가셔 약간의 실마리를 찾으면 바로 문제를 해결할 수 있었다.