BARE METAL 서버 관리하기(2)

TAEWOO HA·2023년 7월 25일
0

Docker

목록 보기
6/7

목표

Django App 개발
Bare Metal 서버의 등록
SSH를 이용한 연결 테스트
Ansible 을 이용한 프로비저닝

  • 장고앱 : setup.py(정보획득) , ansible.py(실행)

  • 개발환경 -> testvm(등록 , 프로비저닝)

Github Sync Fork 수행

자신의 깃헙 Repository로 이동하기

동적 웹 앱 만들기

  • 백엔드 : 데이터 , 서버 관리
  • 프론트엔드 : UI제공
  • 통신 : RestAPI
  • 관리 주체 : Django

  • 파이썬 동적 애플리케이션 웹 서버

  • 동적 : 요청할때마다 상태에 따라서 응답이 변경되는 경우

  • 정적 : 특별한 사건이 없는 한 요청 형태에 관계없이 변동되지 않는다.

  • 파이썬 <=> 웹서버 (CGI Common Gateway Interface) (과거)

    • 프로세스의 실행 결과를 사용자들에게 리턴해줌
  • 서버를 상주시키고 통신하도록 만듦(JAVA)

  • 파이썬도 미리 실행시켜놓음(WSGI)

WSGI

HTTP의 요청과 응답을 추상화.
WSGI 를 전문적으로 처리할 수 있는 엔진 사용 가능
uWSGI, Gunicorn, mod_wsgi, ...
WSGI 를 기반으로 하는 다양한 프레임워크 사용 가능

SQL 데이터베이스를 사용하려면

Python의 SQL 연결 프레임워크를 선택하여 사용
SQLAlchemy 와 같은 솔루션 사용
보다 잘 정리된 구조가 필요하다면?
Flask 와 같은 프레임워크 사용하기

웹 프로그래밍

  • HTTP 프로토콜로 신하는 클라이언트-서버 개발

웹 프로그래밍(2)

웹 클라이언트
HTTP 프로토콜로 서버에 명령을 보내고 콘텐츠를 수신
사람(사용자)과 상호작용을 담당

웹 서버
HTTP 프로토콜로 명령을 수신하고 콘텐츠를 제공
각 종 데이터를 가공 처리

HTTP 프로토콜

인터넷의 웹 기술 규약.
서버와 클라이언트가 명령과 응답을 송수신할 때, 그 내용을 기술하는 방법에 대한 규칙
HTTP는 Hypter-Text Transfer Protocol 약어

HTTP 메서드
GET : Resource를 요청
HEAD : Resource의 헤더만 요청
POST : Resource에 정보 추가
PUT : Resource의 갱신
PATCH : Resource의 일부 변경
DELETE : Resource를 삭제
HTTP 상태 코드
1xx : 조건부 응답
현재, 거의 사용하지 않음
2xx : 성공
요청을 이해하였고, 처리했음의 의미
3xx : 리다이렉션 완료
요청한 리소스의 위치 변경되었음
4xx : 요청에 오류 있음
5xx : 서버에 오류 있음

웹 서버

정적 웹 서버 (nginx , apache)
정적?
어떤 요청에 대해서 정해진 내용을 항상 똑같이 응답한다.
저장된 문서
저장된 이미지
동적 웹 서버 (자바 , C , 파이썬)
동적?
어떤 요청에 따라 응답할 내용이 변경된다.
예: 게시판
URL의 QueryString에 따라, 결과가 다름
URL을 요청한 시점에 따라, 결과가 다름

Django

뼈대 만들기

$ python -m django startproject docker_mgmt_site

docker_mgmt_site 가 프로젝트 이름

  • docker_mgmt_site : 설정 앱(패키지)
  • manage : CLI

개발할 애플리케이션 생성

…/docker_mgmt_site/ $ python manage.py startapp baremetal

baremetal 이라는 앱을 만들어보자.
다른 이름으로 만들고 싶으면 다르고 줄 수 있다.
주의: 이 앱 이름은 파이썬 패키지 이름으로 사용할 수 있는 이름만 사용 가능.

장고 웹 서버 설정을 한번 살펴보자

"""
Django settings for docker_mgmt_site project.

Generated by 'django-admin startproject' using Django 4.2.3.

For more information on this file, see
https://docs.djangoproject.com/en/4.2/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.2/ref/settings/
"""

from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
import os
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get("SECRET KET",'django-insecure-######################')

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'baremetal'
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'docker_mgmt_site.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'docker_mgmt_site.wsgi.application'


# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'docker_mgmt',
        'USER': 'dba',
        'PASSWORD': 'dba@secret',
        'HOST':'mysql',
        'PORT':'3306',
    }
}

#    'default': {
#        'ENGINE': 'django.db.backends.sqlite3',
#        'NAME': BASE_DIR / 'db.sqlite3',
#    }



# Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/

STATIC_URL = 'static/'

# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

import pymysql
pymysql.install_as_MySQLdb()

python manage.py runserver 0.0.0.0:8000

아이디 패스워드 설정

$ python manage.py migrate

python manage.py createsuperuser

Baremetal 앱 개발

디렉토리 구조

manage.py 파일이 있는 곳은 프로젝트 디렉토리
프로젝트 디렉토리이름과 동일한 이름의 디렉토리는
장고 설정을 위한 패키지
baremetal 디렉토리는
baremetal 앱을 위한 패키지

admin.py : 관리페이지에 등록되는 내용 개발
apps.py
models.py : 데이터베이스 모델 개발
tests.py
views.py : 일반 페이지로 구성할 내용 개발

BareMetal 서버를 추가
기존에 만든 docker_mgmt 를 활용
Server 를 등록하면 Database 에 등록하고 관리
Role 을 정적으로 관리
해당 디렉토리를 스캔하여, Role 목록을 관리
Server는 Role 과 관계를 설정
프로비저닝을 지시하면? → Ansible Playbook 실행

기존의 DOCKER_MGMT 포함시켜보기

  • setting.py 수정

    if DEBUG and os.path.exists("/workspace/docker_mgmt"):
       import sys
       sys.path.append("/workspace")
       

    데이터베이스 준비

    …/docker_mgmt_site/ $ python manage.py migrate

    관리 계정을 만들기

    /docker_mgmt_site/ $ python manage.py createsuperuser

    모델 수정 => 데이터 베이스 적용하기

    …/docker_mgmt_site/ $ python manage.py makemigrations
    데이터베이스에 반영할 준비, 구조 변경사항 생성

    만들어보기

    models.py

 from typing import List, Optional
from django.db import models

from docker_mgmt.remotes.setup import Server as _Server
from docker_mgmt.remotes.setup import Disk

class Server(models.Model,_Server):
    hostname: models.CharField(max_length=200)
    ip_address: models.CharField(max_length=200, null=True, blank=True)
    number_of_cores: models.IntegerField(default=1)
    cpu_vendor: models.CharField(max_length=200, null=True, blank=True)
    cpu_model: models.CharField(max_length=200, null=True, blank=True)
    cpu_clocks: models.CharField(max_length=200, null=True, blank=True)
    memory_totals: models.IntegerField(null=True, blank=True)
    disk_info = models.JSONField(default=dict())
    roles = models.ManyToManyField("AnsibleRole")

    def __str__(self) -> str:
        if self.hostname:
            return self.hostname
        return self.ip_address
    

    @property
    def disks(self) -> Optional[List[Disk]]:

        disks = []
        for k,v in self.disk_info.items():
            disk = Disk()
            disk.dev = k
            disk.size = v
            disks.append(disk)
        return disks
    
class AnsibleRole(models.Model):
    name = models.CharField(max_length=200)
    path = models.CharField(max_length=250, unique=True)
    description = models.TextField(null=True, blank=True)

    def __str__(self) -> str:
        return self.name
    
class Menu(models.Model):
#    list_display = ['Menuname','Price','Quantity']
#    search_fields = ['Menuname','Price','Quantity']
    Menuname = models.CharField(max_length=200)
    Price = models.PositiveIntegerField()
    Quantity = models.PositiveIntegerField()
#    editable_list = ['Quantity']

    def __str__(self):
        return self.Menuname

    @property
    def price_with_dollar(self):
        return f"${self.Price}"

admin.py

from django.contrib import admin
from .models import Server, AnsibleRole, Menu

class MenuAdmin(admin.ModelAdmin):
    list_display = ['Menuname', 'price_with_dollar', 'Quantity']
    search_fields = ['Menuname', 'Price', 'Quantity']
    list_editable = ['Quantity']

admin.site.register(Server)
admin.site.register(AnsibleRole)
admin.site.register(Menu, MenuAdmin)
# Register your models here.

  • 결과
    • 공식 문서를 보면서 만들어보니 재밌다.

0개의 댓글