Django App 개발
Bare Metal 서버의 등록
SSH를 이용한 연결 테스트
Ansible 을 이용한 프로비저닝
장고앱 : setup.py(정보획득) , ansible.py(실행)
개발환경 -> testvm(등록 , 프로비저닝)
자신의 깃헙 Repository로 이동하기
파이썬 동적 애플리케이션 웹 서버
동적 : 요청할때마다 상태에 따라서 응답이 변경되는 경우
정적 : 특별한 사건이 없는 한 요청 형태에 관계없이 변동되지 않는다.
파이썬 <=> 웹서버 (CGI Common Gateway Interface) (과거)
서버를 상주시키고 통신하도록 만듦(JAVA)
파이썬도 미리 실행시켜놓음(WSGI)
HTTP의 요청과 응답을 추상화.
WSGI 를 전문적으로 처리할 수 있는 엔진 사용 가능
uWSGI, Gunicorn, mod_wsgi, ...
WSGI 를 기반으로 하는 다양한 프레임워크 사용 가능
Python의 SQL 연결 프레임워크를 선택하여 사용
SQLAlchemy 와 같은 솔루션 사용
보다 잘 정리된 구조가 필요하다면?
Flask 와 같은 프레임워크 사용하기
- 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을 요청한 시점에 따라, 결과가 다름
$ 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
디렉토리 구조
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 실행
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
데이터베이스에 반영할 준비, 구조 변경사항 생성
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}"
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.