Skip to content

Commit

Permalink
Merge pull request #34 from Algo-Sports/develop
Browse files Browse the repository at this point in the history
Deploy
  • Loading branch information
Aqudi authored Dec 14, 2020
2 parents 2a826ba + e432041 commit 567f60c
Show file tree
Hide file tree
Showing 113 changed files with 4,402 additions and 418 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ env:

on:
pull_request:
branches: [ "master" ]
branches: [ "master", "develop" ]
paths-ignore: [ "docs/**" ]

push:
branches: [ "master" ]
branches: [ "master", "develop" ]
paths-ignore: [ "docs/**" ]


Expand Down Expand Up @@ -56,4 +56,4 @@ jobs:
run: docker-compose -f local.yml exec -T django pytest

- name: Tear down the Stack
run: docker-compose down
run: docker-compose -f local.yml down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
match_datas

### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
Expand Down
184 changes: 181 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,191 @@
# AlgoSports Backend

## Development

## Installation
### Branch

- 아래 포스트의 convention을 일부 차용해서 사용한다.
- https://dev.to/couchcamote/git-branching-name-convention-cch

## Development
1. master
- 실제 배포
2. develop
- 개발 및 테스트
3. temporary branches

- feat/<branch_name>
- 기능 개발을 다루는 branch.
- bugfix/<branch_name>
- feature에서 발생한 버그를 다루는 branch.
- hotfix/<branch_name>
- master 브랜치에 바로 반영해야하는 버그를 다루는 branch.
- experimental/<branch_name>
- 테스트하고 싶은 기능을 다루는 branch.

### Installation

1. Activate virtual environment
2. Install packages
```shell
pip install -r requirements/local.txt
```

### Utility

## Test
- 아래 커맨드로 확인 가능

```shell
fab -l
```

### Start local server

- API 서버
```shell
fab runserver
```
- Celery broker
```shell
redis-server
```
- Celery worker
```shell
fab celery
```

### Test

```shell
pytest .
mypy .
```

## Build & Deploy

### 사전 준비물

- AWS CLI2 설치
```shell
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
```
- ECS-CLI 설치
```shell
sudo curl -Lo /usr/local/bin/ecs-cli https://amazon-ecs-cli.s3.amazonaws.com/ecs-cli-linux-amd64-latest
sudo chmod +x /usr/local/bin/ecs-cli
```
- IAM 계정 생성 및 정책 연결
![IAM_정책](./docs/IAM_정책.png)

### ECS-CLI로 클러스터 생성

- 생성 후 만들어진 VPC, Subnets을 저장해둬야 합니다.
- key-pair를 먼저 생성하고 key-pair이름을 저장해둡니다.

```shell
# 환경변수 설정
AWS_DEFAULT_REGION=ap-northeast-2
CLUSTER_NAME=algo-cluster2
CONFIG_NAME=algo-config
PROFILE_NAME=algo-profile
INSTANCE_SIZE=3

KEY_PAIR=algo-keypair

# 클러스터 및 프로필 설정
ecs-cli configure --cluster $CLUSTER_NAME --region $AWS_DEFAULT_REGION --default-launch-type EC2 --config-name $CONFIG_NAME
ecs-cli configure profile --access-key $AWS_ACCESS_KEY_ID --secret-key $AWS_SECRET_ACCESS_KEY --profile-name $PROFILE_NAME
ecs-cli configure profile default --profile-name $PROFILE_NAME

# user-data 생성 (ecs-cluster에 연결하는 역할)
echo "#!/bin/bash \necho ECS_CLUSTER=jts-cluster >> /etc/ecs/ecs.config" > user_data.sh

# 클러스터 생성
ecs-cli up \
--capability-iam \
--keypair $KEY_PAIR \
--size $INSTANCE_SIZE \
--launch-type EC2 \
--extra-user-data ./aws/user_data.sh
```

### Security Group 생성 및 80포트 오픈

```shell
VPC_ID=<Your VPC ID Here>
SG_NAME=algo-sg

# Security group 생성 및 GROUP_ID 저장
SG_GROUP_ID=$(aws ec2 create-security-group \
--group-name "$SG_NAME" \
--description "Security Group for ECS $CLUSTER_NAME" \
--vpc-id $VPC_ID |
jq -r ".GroupId")

aws ec2 authorize-security-group-ingress \
--group-id $SG_GROUP_ID \
--protocol tcp \
--port 80 \
--cidr 0.0.0.0/0
```

### ECR 로그인 및 레포지토리 생성

```shell
# ECR 레포지토리 생성
aws ecr create-repository --repository-name django |
jq ".repository | .repositoryUri"

aws ecr create-repository --repository-name nginx |
jq ".repository | .repositoryUri"
```

### ECR 저장소 이미지 배포

```shell
# ECR, Docker 로그인
aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $(aws sts get-caller-identity --query Account --output text).dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/

docker-compose -f staging.yml -f production.yml build
docker-compose -f staging.yml -f production.yml push django nginx
```

### ECS Task IAM role 생성

```shell
# 빈 iam role 생성
aws iam create-role --role-name ecs-instance --assume-role-policy-document file://aws/assume-role.json

# 필요한 정책 추가
aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role --role-name ecs-instance

# 인스턴스 프로필 생성
aws iam create-instance-profile --instance-profile-name ecs-instance-profile

# 해당 프로필에 롤 추가
aws iam add-role-to-instance-profile --instance-profile-name ecs-instance-profile --role-name ecs-instance

# instasnce profiles 출력
aws iam list-instance-profiles
```

### 서비스 생성

```shell
CONFIG_NAME=algo-config
PROJECT_NAME=algo-service

ecs-cli compose \
--project-name $PROJECT_NAME \
--file staging.yml \
--file production.yml \
--ecs-params ./aws/ecs-params.yml \
service up \
--create-log-groups \
--cluster-config $CONFIG_NAME \
--container-name nginx \
--container-port 80 \
--target-group-arn arn:aws:elasticloadbalancing:ap-northeast-2:648240308375:targetgroup/target/e3086c4f494a30c4 \
--launch-type EC2
```
Empty file added algo_sports/blogs/__init__.py
Empty file.
18 changes: 18 additions & 0 deletions algo_sports/blogs/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from django.contrib import admin

from .models import Blog, Comment, Post


@admin.register(Blog)
class BlogAdmin(admin.ModelAdmin):
pass


@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
pass


@admin.register(Comment)
class CommentAdmin(admin.ModelAdmin):
pass
7 changes: 7 additions & 0 deletions algo_sports/blogs/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _


class BlogConfig(AppConfig):
name = "algo_sports.blogs"
verbose_name = _("Blogs")
30 changes: 30 additions & 0 deletions algo_sports/blogs/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from django_filters import rest_framework as filters
from django_filters.filters import CharFilter

from .models import Blog, Comment, Post


class BlogFilter(filters.FilterSet):
class Meta:
model = Blog
fields = (
"category",
"permission",
)


class PostFilter(filters.FilterSet):
blog = CharFilter(field_name="blog_id__category")

class Meta:
model = Post
fields = ("title",)


class CommentFilter(filters.FilterSet):
class Meta:
model = Comment
fields = (
"post_id",
"parent_id",
)
60 changes: 60 additions & 0 deletions algo_sports/blogs/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Generated by Django 3.1.3 on 2020-11-17 21:58

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name='Blog',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('category', models.CharField(max_length=2, verbose_name='Blog cateogry')),
('permission', models.CharField(choices=[('AD', 'Admin only'), ('ST', 'Staff only'), ('AL', 'Allow any')], default='AL', max_length=2, verbose_name='Blog permission')),
('description', models.TextField(max_length=2, verbose_name='Blog description')),
],
options={
'ordering': ['category'],
},
),
migrations.CreateModel(
name='Post',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.TextField(verbose_name='Post title')),
('content', models.TextField(verbose_name='Post content')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('blog_id', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='posts', to='blogs.blog', verbose_name='Post of comment')),
('user_id', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='posts', to=settings.AUTH_USER_MODEL, verbose_name='Post author')),
],
options={
'ordering': ['-id'],
},
),
migrations.CreateModel(
name='Comment',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('deleted', models.BooleanField(default=False, verbose_name='Is Comment deleted?')),
('content', models.CharField(max_length=300, verbose_name='Comment content')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('parent_id', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='childs', to='blogs.comment', verbose_name='Parent Comment')),
('post_id', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='comments', to='blogs.post', verbose_name='Comment of post')),
('user_id', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='comments', to=settings.AUTH_USER_MODEL, verbose_name='Comment author')),
],
options={
'ordering': ['-id'],
},
),
]
29 changes: 29 additions & 0 deletions algo_sports/blogs/migrations/0002_auto_20201119_0024.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Generated by Django 3.1.3 on 2020-11-19 00:24

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('blogs', '0001_initial'),
]

operations = [
migrations.AlterField(
model_name='blog',
name='category',
field=models.SlugField(max_length=2, unique=True, verbose_name='Blog cateogry'),
),
migrations.AlterField(
model_name='blog',
name='permission',
field=models.PositiveSmallIntegerField(choices=[(3, 'Admin only'), (2, 'Staff only'), (1, 'Allow any')], default=1, verbose_name='Blog permission'),
),
migrations.AlterField(
model_name='post',
name='blog_id',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='posts', to='blogs.blog', verbose_name='Blog of post'),
),
]
28 changes: 28 additions & 0 deletions algo_sports/blogs/migrations/0003_auto_20201120_1843.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Generated by Django 3.1.3 on 2020-11-20 18:43

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('blogs', '0002_auto_20201119_0024'),
]

operations = [
migrations.AlterField(
model_name='blog',
name='category',
field=models.SlugField(unique=True, verbose_name='Blog cateogry'),
),
migrations.AlterField(
model_name='blog',
name='description',
field=models.CharField(max_length=200, verbose_name='Blog description'),
),
migrations.AlterField(
model_name='post',
name='title',
field=models.CharField(max_length=200, verbose_name='Post title'),
),
]
Loading

0 comments on commit 567f60c

Please sign in to comment.