본문 바로가기

Cloud/Oracle Cloud Infrastructure (OCI)

OCI Kubernetes와 MySQL 서비스를 활용한 어플리케이션 배포 데모 - #4. OCI 레지스트리 설정, 도커 이미지 빌드

글 순서

#1. OKE 클러스터 설치

#2. MySQL 서비스 배포

#3. 쿠버네티스 접속 환경 구성

#4. OCI 레지스트리 설정, 도커 이미지 빌드

#5. 도커 이미지 OCIR에 등록, OKE 클러스터에 컨테이너 배포

 

OCI 레지스트리 설정

빌드된 어플리케이션 컨테이너 이미지를 OCI 레지스트리에 push/pull 하기 위한 설정입니다.

 

인증 토큰 생성

OCI 레지스트리에 접근하려면 OCI 레지스트리 접속 패스워드 기능을 하는 인증 토큰 (Auth Token)이 필요합니다. 인증 토큰은 OCI 웹 콘솔에서 생성할 수 있습니다. OCI 웹 콘솔 오른쪽 상단의 사용자 메뉴를 클릭하면 나오는 User Settings 화면으로 이동합니다.

 

Auth Tokens 화면에서 Generate Token을 클릭하면 나오는 팝업창에서 인증 토큰에 대한 설명을 입력하고 Generate Token을 클릭합니다. 여기서는 “demo auth token”이라고 입력했습니다.

 

인증 토큰 값은 OCI 웹 콘솔에서 다시 조회가 되지 않기 때문에 생성된 인증 토큰을 즉시 복사해서 따로 저장해 둡니다.이는 이후 OCI 레지스트리에 접속할 때 사용됩니다. 인증 토큰을 복사 한 다음, Close를 클릭하여 팝업창을 닫습니다.

 

OCI 레지스트리 로그인

이제 OCI 레지스트리에 로그인을 테스트합니다. 아래 포맷으로 접속합니다.

docker login -u '<tenancy-namespace>/<user-name>' <region-key>.ocir.io

만일 사용 중인 테넌시가 Oracle Identity Cloud Service와 federation되어 있다면 아래 포맷으로 접속합니다.

docker login -u '<tenancy-namespace>/oracleidentitycloudservice/<username>' <region-key>.ocir.io

패스워드 입력 프롬프트에는 앞서 생성한 OCI 인증 토큰 값을 입력합니다.

[opc@bastion ~]$ docker login -u idzaf7d76gjx/oracleidentitycloudservice/username@sample.com iad.ocir.io
Password:
WARNING! Your password will be stored unencrypted in /home/opc/.docker/config.json.
Configure a credential helper to remove this warning. See
<https://docs.docker.com/engine/reference/commandline/login/#credentials-store>

Login Succeeded

 

쿠버네티스 시크릿 파일 생성

OKE 클러스터에 로그인하는 정보를 시크릿 파일로 만들어서 추후 클러스터에 어플리케이션을 배포할 때 사용합니다. 아래와 같이 시크릿 파일을 생성합니다.

[opc@bastion ~]$ kubectl create secret docker-registry ocirsecret --docker-server=iad.ocir.io --docker-username='idzaf7d76gjx/oracleidentitycloudservice/username@sample.com' --docker-password='y1h]p)y3xw{LCv6-tw}z' --docker-email='username@sample.com'
secret/ocirsecret created
[opc@bastion ~]$ kubectl get secrets
NAME                  TYPE                                  DATA   AGE
default-token-cczrr   kubernetes.io/service-account-token   3      25h
ocirsecret            kubernetes.io/dockerconfigjson        1      10s

 

도커 이미지 빌드

어플리케이션을 컨테이너로 전환

먼저 git clone 명령으로 GitHub에 올린 어플리케이션 소스 코드, 패키지 정보, 도커와 쿠버네티스 매니페스트 파일을 아래와 같이 로컬에 복제합니다.

[opc@bastion ~]$ git clone <https://github.com/ykyunjung/python-mysql-sample.git>
Cloning into 'python-mysql-sample'...
remote: Enumerating objects: 9, done.
remote: Counting objects: 100% (9/9), done.
remote: Compressing objects: 100% (7/7), done.
remote: Total 9 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (9/9), done.
[opc@bastion ~]$ ls
~  bin  cluster-state  dbconn.py  kubectl  lib  python-mysql-sample
[opc@bastion python-mysql-sample]$ ls
Dockerfile  main.py  requirements.txt

 

각 파일의 내용입니다.

먼저 파이썬 코드입니다. Flask를 이용해서 파이썬 웹서버를 띄우고 있습니다. 그리고 데이터베이스에 접속해서 메타정보를 가져오고 있습니다.

[opc@bastion python-mysql-sample]$ cat main.py
from flask import Flask
import logging
import json
import pymysql

app = Flask(__name__)

dbhost = '10.0.30.52'
dbuser = 'root'
dbpassword = 'Welcome123!@'
dbname = 'mysql'

logger = logging.getLogger()
logger.setLevel(logging.INFO)

conn = pymysql.connect(host=dbhost, user=dbuser, password=dbpassword, db=dbname, connect_timeout=5)

@app.route("/")
def list_data():
    try:
        cursor = conn.cursor()
        sql = "select version(), current_date, user()"
        cursor.execute(sql)
    except Exception as ex:
        logger.error("ERROR: Could not fetch data.")
        logger.error(e)

    logger.info("SUCCESS: Fetching data succeeded")

    results = cursor.fetchall()
    json_data = json.dumps(results, default=str)

    cursor.close()

    return json_data

print(list_data())

if __name__ == "__main__":
    app.run(host='0.0.0.0')

 

설치할 패키지 정보 파일에서 Flask와 PyMySQL을 정의하고 있습니다.

[opc@bastion python-mysql-sample]$ cat requirements.txt
Flask
PyMySQL

 

도커 파일의 내용입니다.

  • 파이썬 베이스 이미지 (3.6)을 도커 허브에서 가져옵니다.
  • 이미지에서 app 이라는 이름의 디렉토리를 생성합니다.
  • 생성한 디렉토리 app을 작업 디렉토리로 지정합니다.
  • 로컬 디렉토리의 내용을 이미지 안의 새로 생성된 디렉토리에 복사합니다.
  • pip 명령으로 requirements.txt 파일에 정의된 패키지들를 이미지 안으로 가져옵니다.
  • 도커 컨테이너가 5000 번 포트을 사용하도록 합니다.
  • 컨테이너가 시작될 때 사용할 시작 명령을 정의합니다.
[opc@bastion python-mysql-sample]$ cat Dockerfile
FROM python:3.6

RUN mkdir /app
WORKDIR /app
ADD . /app/
RUN pip install -r requirements.txt

EXPOSE 5000
CMD ["python", "/app/main.py"]

 

python-mysql-sample.yaml 파일의 내용은 OKE 클러스터 배포 부분에서 다시 살펴보겠습니다.

 

Bastion 호스트 로컬에서 코드가 정상 작동하는지 먼저 테스트하기 위해 requirements.txt에 정의된 패키지를 설치합니다.

[opc@bastion python-mysql-sample]$ sudo pip3 install -r requirements.txt
...
Installing collected packages: typing-extensions, zipp, importlib-metadata, click, dataclasses, Werkzeug, itsdangerous, MarkupSafe, Jinja2, Flask
Successfully installed Flask-2.0.3 Jinja2-3.0.3 MarkupSafe-2.0.1 Werkzeug-2.0.3 click-8.0.4 dataclasses-0.8 importlib-metadata-4.8.3 itsdangerous-2.0.1 typing-extensions-4.1.1 zipp-3.6.0

 

코드가 정상 작동하는 지 확인합니다. 웹서버가 실행된 것을 확인 후 CTRL+C로 exit합니다.

[opc@bastion python-mysql-sample]$ python main.py
[["8.0.29-cloud", "2022-05-26", "root@10.0.0.3"]]
 * Serving Flask app 'main' (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on all addresses.
   WARNING: This is a development server. Do not use it in a production deployment.
 * Running on <http://10.0.0.3:5000/> (Press CTRL+C to quit)
^C[opc@bastion python-mysql-sample]$

 

도커 이미지 생성

“python-mysql-sample” 라는 이름으로 도커 이미지를 생성했습니다.

[opc@bastion python-mysql-sample]$ docker build -f Dockerfile -t python-mysql-sample:latest .
Sending build context to Docker daemon  61.44kB
Step 1/7 : FROM python:3.6
Trying to pull repository docker.io/library/python ...
3.6: Pulling from docker.io/library/python
0e29546d541c: Pull complete
9b829c73b52b: Pull complete
cb5b7ae36172: Pull complete
6494e4811622: Pull complete
6f9f74896dfa: Pull complete
5e3b1213efc5: Pull complete
9fddfdc56334: Pull complete
404f02044bac: Pull complete
c4f42be2be53: Pull complete
Digest: sha256:f8652afaf88c25f0d22354d547d892591067aa4026a7fa9a6819df9f300af6fc
Status: Downloaded newer image for python:3.6
 ---> 54260638d07c
Step 2/7 : RUN mkdir /app
 ---> Running in 27ca951dade1
Removing intermediate container 27ca951dade1
 ---> 2dcd2af8c283
Step 3/7 : WORKDIR /app
 ---> Running in e220cb0df60d
Removing intermediate container e220cb0df60d
 ---> b71e9f9cdb12
Step 4/7 : ADD . /app/
 ---> 7a40f261bda3
Step 5/7 : RUN pip install -r requirements.txt
 ---> Running in 82a7c7eb74da
Collecting Flask
  Downloading Flask-2.0.3-py3-none-any.whl (95 kB)
Collecting PyMySQL
  Downloading PyMySQL-1.0.2-py3-none-any.whl (43 kB)
Collecting click>=7.1.2
  Downloading click-8.0.4-py3-none-any.whl (97 kB)
Collecting Werkzeug>=2.0
  Downloading Werkzeug-2.0.3-py3-none-any.whl (289 kB)
Collecting itsdangerous>=2.0
  Downloading itsdangerous-2.0.1-py3-none-any.whl (18 kB)
Collecting Jinja2>=3.0
  Downloading Jinja2-3.0.3-py3-none-any.whl (133 kB)
Collecting importlib-metadata
  Downloading importlib_metadata-4.8.3-py3-none-any.whl (17 kB)
Collecting MarkupSafe>=2.0
  Downloading MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (30 kB)
Collecting dataclasses
  Downloading dataclasses-0.8-py3-none-any.whl (19 kB)
Collecting typing-extensions>=3.6.4
  Downloading typing_extensions-4.1.1-py3-none-any.whl (26 kB)
Collecting zipp>=0.5
  Downloading zipp-3.6.0-py3-none-any.whl (5.3 kB)
Installing collected packages: zipp, typing-extensions, MarkupSafe, importlib-metadata, dataclasses, Werkzeug, Jinja2, itsdangerous, click, PyMySQL, Flask
Successfully installed Flask-2.0.3 Jinja2-3.0.3 MarkupSafe-2.0.1 PyMySQL-1.0.2 Werkzeug-2.0.3 click-8.0.4 dataclasses-0.8 importlib-metadata-4.8.3 itsdangerous-2.0.1 typing-extensions-4.1.1 zipp-3.6.0
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: <https://pip.pypa.io/warnings/venv>
WARNING: You are using pip version 21.2.4; however, version 21.3.1 is available.
You should consider upgrading via the '/usr/local/bin/python -m pip install --upgrade pip' command.
Removing intermediate container 82a7c7eb74da
 ---> 094cde9bcba8
Step 6/7 : EXPOSE 5000
 ---> Running in b880f0dc9568
Removing intermediate container b880f0dc9568
 ---> b68299a3abff
Step 7/7 : CMD ["python", "/app/main.py"]
 ---> Running in c491b5350752
Removing intermediate container c491b5350752
 ---> 077655efba8c
Successfully built 077655efba8c
Successfully tagged python-mysql-sample:latest[opc@bastion python-mysql-sample]$ docker images
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
python-mysql-sample   latest              077655efba8c        19 seconds ago      913MB
python                3.6                 54260638d07c        5 months ago        902MB

 

생성된 도커 이미지를 확인합니다.

[opc@bastion python-mysql-sample]$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
list-data           latest              fcd2f3f56610        54 seconds ago      913MB
python              3.6                 54260638d07c        5 months ago        902MB

 

docker run 명령을 실행하여 컨테이너가 정상 작동하는 지 확인합니다.

[opc@bastion python-mysql-sample]$ docker run -p 5001:5000 python-mysql-sample
[["8.0.29-cloud", "2022-05-26", "root@10.0.0.3"]]
 * Serving Flask app 'main' (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on all addresses.
   WARNING: This is a development server. Do not use it in a production deployment.
 * Running on <http://172.17.0.2:5000/> (Press CTRL+C to quit)

 

위에서 웹서버가 실행되면 터미널을 하나 더 열어서 아래와 같이 curl 명령으로 어플리케이션이 정상 작동하는지 확인합니다.

[opc@bastion python-mysql-sample]$ curl <http://localhost:5001>
[["8.0.29-cloud", "2022-05-26", "root@10.0.0.3"]

 

CTRL+C을 눌러 첫번째 터미널의 Flask 어플리케이션을 종료합니다.

 

<END>