My Wiki!

Development Environment

1. Preparing K8S dev

1.1 Create project from cookiecutter-django template

Create virtual env

  python3 -m venv project_venv
  source project_venv/bin/activate
  
  pip install cookiecutter
  

Create new project from template:

  cookiecutter https://github.com/pydanny/cookiecutter-django.git
  

Follow cookiecutter-django docs https://cookiecutter-django.readthedocs.io/en/3.0.5-01/project-generation-options.html

1.2 Use minikube docker-env

Make sure minikube is started:

  docker info | grep Name
  Name: localhost.localdomain

Localhost docker context is activated so start minikube:

minikube start --vm-driver=kvm2 --memory='4g'

Using minikube docker context (for each bash console):

eval $(minikube docker-env)

docker info | grep Name
Name: minikube

1.3 Quick troubleshooting

Logs:

  docker-compose -f local.yml logs
  

Cleanup.

  docker stop $(docker ps -a -q)

Remove volume mount and images.

  docker-compose -f local.yml down --rmi all -v
  docker builder prune
  docker system prune -a
  docker-compose -f local.yml build
  docker-compose -f local.yml up
  
  

Local development

1. Build project with docker

Build project:

  docker-compose -f local.yml build
  

Start containers:

  docker-compose -f local.yml up

Output from the containers

  
  django          | INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
  node            | [Browsersync] Proxying: http://django:8000
  node            | [Browsersync] Access URLs:
  node            |  -----------------------------------
  node            |        Local: http://localhost:3000
  node            |     External: http://172.19.0.9:3000
  node            |  -----------------------------------
  node            |           UI: http://localhost:3001
  node            |  UI External: http://localhost:3001
  node            |  -----------------------------------

2. Accessing the web page

The containers are started on docker host, which is seen by the containers as localhost. If local docker is used the host ports are forwarded to the containers so localhost 127.0.0.1 is used to access the web page. If minikube docker context is used. We need to figure out the minikube host IP:

  
  kubectl get nodes -o wide
  NAME       STATUS   ROLES    AGE   VERSION   INTERNAL-IP      EXTERNAL-IP   OS-IMAGE              KERNEL-VERSION   CONTAINER-RUNTIME
  minikube   Ready    master   42h   v1.16.2   192.168.39.208   <none>        Buildroot 2019.02.6   4.19.76          docker://18.9.9

In this example 192.168.39.208 is the docker host IP. Add this to Django ALLOWED HOSTS.

3. Run command inside the containers

As with any shell command that we wish to run in our container, this is done using the docker-compose -f local.yml run –rm command:

docker-compose -f local.yml run --rm django python manage.py migrate
docker-compose -f local.yml run --rm django python manage.py createsuperuser

Run interactive shell:

  docker exec -ti django /bin/bash

4. How the containers interact

docker ps -a
CONTAINER ID        IMAGE                               COMMAND                  CREATED             STATUS                           PORTS                              NAMES
a8a9de7b744c        django_maxo36_local_node            "docker-entrypoint.s…"   31 minutes ago      Up 31 minutes                    0.0.0.0:3000-3001->3000-3001/tcp   node
84204e207978        django_maxo36_local_django          "/entrypoint /start"     31 minutes ago      Up 31 minutes                    0.0.0.0:8000->8000/tcp             django
3413c2e66f7f        django_maxo36_local_celeryworker    "/entrypoint /start-…"   31 minutes ago      Up 31 minutes                                                       celeryworker
d83d03753d78        django_maxo36_local_flower          "/entrypoint /start-…"   31 minutes ago      Up 31 minutes                    0.0.0.0:5555->5555/tcp             flower
148ba234b996        django_maxo36_local_celerybeat      "/entrypoint /start-…"   31 minutes ago      Up 31 minutes                                                       celerybeat
0771470a42ce        django_maxo36_production_postgres   "docker-entrypoint.s…"   18 hours ago        Up 31 minutes                    5432/tcp                           postgres
41cad252130a        mailhog/mailhog:v1.0.0              "MailHog"                18 hours ago        Up 31 minutes                    1025/tcp, 0.0.0.0:8025->8025/tcp   mailhog
ba5e14f8a6a5        redis:5.0                           "docker-entrypoint.s…"   18 hours ago        Up 31 minutes                    6379/tcp                           redis

5. Volume mount to minikube

Using local docker context we can mount host folders to docker image. This is useful for developing cloud native apps because we don't need to copy source code and rerun container build when the code is updated. Local folder can be mounted as following.

For docker run:

docker run \
--rm \
-it \
--mount \
type=bind,\
source="$(pwd)",\
target="/app" \
django_maxo36_local_django:latest

For docker-compose:

version: '3' 

volumes:
  local_postgres_data: {}
  local_postgres_data_backups: {}

services:
  django: &django
    build:
      context: .
      dockerfile: ./compose/local/django/Dockerfile
    image: django_maxo36_local_django
    container_name: django
    depends_on:
      - postgres
      - mailhog
    volumes:
      # path to source minikube/docker local-path mount
      # https://stackoverflow.com/questions/48534980/mount-local-directory-into-pod-in-minikube
      - .:/app        <------- THIS IS IT
    env_file:
      - ./.envs/.local/.django
      - ./.envs/.local/.postgres
    ports:
      - "8000:8000"
    command: /start

The current folder will be mounted as /app in the container. This however only works with local docker context. If the folder should be mounted on a remote docker host or e.g., minikube VM, we need a different way to sync local folders.

5.1 Option 1

For minikube, we can mount the local folder on minikube at a defaul localtion in the minikube VM and use hostPath to mount the VM folder location to the pod / container deployed with minikube docker context.

First, mounting local folder to minikube:

  minikube start --mount-string /<host-directory-path>:/<desired-minikube-directory-path> --mount

For an already running minikube you can do the following:

  nohup minikube mount /<host-directory-path>:/<desired-minikube-directory-path> &
  

By default minikube already mount homeDir to the VM:

  • on Mac it mounts dir of all users - /Users
  • on Linux and Windows just the home of current user - homedir.HomeDir()

The definition of the HomeDir() is: https://godoc.org/k8s.io/client-go/util/homedir

You can always do minikube ssh into the Minikube VM and explore it:

  minikube ssh
  df -hl
  Filesystem      Size  Used Avail Use% Mounted on
  ...
  /Users          466G  442G   25G  95% /Users
  

Now we can mount the folder on VM to the pod:

apiVersion: v1
kind: Service
...
---

apiVersion: apps/v1
kind: Deployment
...
spec:
  replicas: 1
  ...
  template:
    ...
    spec:
      containers:
      ...
      volumeMounts:
      - name: someName
        mountPath: /<desired-minikube-directory-path>
    ...
    volumes:
    - name: someName
      hostPath:
        path: /<desired-minikube-directory-path>

Or use the VM path in docker-compose yaml.

More information here

5.2 Option 2 - Mutagen.io

The previous approach depends on docker host's local folder, e.g., minikube mount. There are tools to allow syncing directly a local folder with remote pod or containers:

  • ksync
  • docker-sync
  • Mutagen

We will try Mutagen.

5.2.1 Mutagen Design

Mutagen is designed and operated around the concept of individual synchronization and forwarding sessions. Each session operates between two endpoints. In the case of synchronization, these endpoints are file system locations, and in the case of forwarding, these endpoints are network endpoints. What makes Mutagen uniquely powerful is that sessions can combine any pair of endpoints, regardless of their location or access mechanism.

Common usage scenarios include synchronizing source code from your laptop to a remote server or container, or forwarding requests from local TCP endpoints to remote web servers. But Mutagen can also do things like synchronize files between two remote filesystems using the local system as a proxy, or perform reverse tunneling from a remote system to a service running on your laptop. If you have a problem where you need to synchronize files efficiently or forward network traffic flexibly, then Mutagen can most likely be used to solve it.

5.2.2 Installation

  wget https://github.com/mutagen-io/mutagen/releases/download/v0.11.4/mutagen_linux_amd64_v0.11.4.tar.gz
  tar -xvzf mutagen_linux_amd64_v0.11.4.tar.gz 
  mutagen
  mutagen-agents.tar.gz
  sudo mv mutagen mutagen-agents.tar.gz /usr/local/bin
  

It is important to keep the mutagen-agent tar in the same location as mutagen binary. The agent will be extracted and injected to remote container.

5.2.3 Usage

Note: Docker container must be started with the first version of the code first. I.e., Django src must be copied in order for the container to be started.

Create sync session between localhost and docker host

  mutagen sync create --name=web-app-code ~/src docker://[<user>@]<container>/<path>

The <user> component is optional and tells Mutagen to act as the specified user inside the container. If unspecified, Mutagen uses the default container user (usually root for Linux containers or ContainerAdministrator for Windows containers).

The <container> component can specify any type of container identifier understood by docker cp and docker exec (for example, a container name or hexidecimal identifier).

Note: named local volume should be used for persisted files across docker (compose) run.

Example, for the following docker-compose yaml we will create mutagen sync session:

code
volumes:
  local_postgres_data: {}
  local_postgres_data_backups: {}
  local_django_app: {}
  local_node_app: {}

services:
  django: &django             
    build:
      context: .
      dockerfile: ./compose/local/django/Dockerfile
    image: django_maxo36_local_django
    container_name: django               <--- Mutagen docker transport 
    depends_on:
      - postgres
      - mailhog
    volumes:
      # path to source minikube/docker local-path mount
      # https://stackoverflow.com/questions/48534980/mount-local-directory-into-pod-in-minikube
      - local_django_app:/app         <--- LOCAL and mount point
    env_file:
      - ./.envs/.local/.django
      - ./.envs/.local/.postgres
    ports:
      - "8000:8000"
    command: /start

Creating mutagen sync:

  mutagen sync create --ignore-vcs --name=maxo36-django-src . docker://django/app
  Created session sync_6RvzLrjeAz21vecYh1WwlcAA2d0hh2V2tKTeEoChFiB
  

Managing session:

mutagen sync list
--------------------------------------------------------------------------------
Name: maxo36-django-src
Identifier: sync_6RvzLrjeAz21vecYh1WwlcAA2d0hh2V2tKTeEoChFiB
Labels: None
Alpha:
	URL: /data/workspace/73_maxo36/django_maxo36
	Connection state: Connected
Beta:
	URL: docker://django/app
		DOCKER_HOST=tcp://192.168.39.208:2376
		DOCKER_TLS_VERIFY=1
		DOCKER_CERT_PATH=/home/dang/.minikube/certs
	Connection state: Connected
Status: Watching for changes
    
mutagen sync [monitor|pause|resume|flush|reset|terminate] maxo36-django-src

More details here and transport protocols here.

5.2.4 Mutagen ignore

Some problems caused by syncing dot folder, e.g., git. Using –ignore-vcs flag to the create command and on a default basis by including the following configuration in ~/.mutagen.yml:

sync:
  defaults:
    ignore:
      vcs: true

Check:

  docker-compose -f local.yml run --rm django bash
  

5.2.5 Conflict resolution for synced files

Conflicts (which can occur in two-way-safe and one-way-safe modes) can be resolved manually by deleting the content on the endpoint which you wish to have lose the conflict. Once deleted, the conflict will no longer exist since deletions can be overwritten.

docker-compose -f local.yml run --rm django bash
rm config/settings/local.py

Mutagen will copy local file to django container.

5.2.6 Rebuild images

Trying to update an existing volume with the contents from a new image does not work.

https://docs.docker.com/engine/tutorials/dockervolumes/#/data-volumes

States:

Changes to a data volume will not be included when you update an image.

In case update to setting make django failed to start (so mutagen can not sync), we need to rebuild image from scratch. This is not working:

docker-compose -f local.yml build --no-cache django

Because named volumes are not removed when rebuilding images, we have to remove the volumes first:

  docker-compose -f local.yml down --rmi all -v \
  && docker-compose build --no-cache \
  && docker-compose -f docker-compose-staging.yml up -d --force-recreate
  

ref: https://stackoverflow.com/questions/41498336/docker-copy-not-updating-files-when-rebuilding-container

5.2.7 Similar tools

5.2.8 others

  • 5.2.9 CI/CD

  • 5.2.9.1 Chat CI CD tools

    <code> Sa Pham2:12 PM chắc quen với TF hơn =)) ĐẠI ĐẶNG VĂN2:13 PM mình dùng heat openstack nên nhìn quen quen Cloudformation hơn :v Trinh Nguyen2:13 PM LOL Công Hà Minh2:16 PM Teraform có vẻ gọn gàng dễ đọc hơn Cloud Formation nhỉ các bác. Sa Pham2:17 PM TF ngon hơn Heat :D Công Hà Minh2:19 PM Heat Template dài như cái sớ luôn :( Trinh Nguyen2:22 PM Nice Sa Pham2:25 PM Vậy dev care luôn hạ tầng nhỉ :D ĐẠI ĐẶNG VĂN2:25 PM Hoặc ông hạ tầng phải biết dev :v Công Hà Minh2:26 PM Cái CDK này vẫn phải học xem từng class có ý nghĩa gì, mỗi method trong class có những tham số gì, ý nghĩa của từng tham số là gì các bác nhỉ? Trinh Nguyen2:27 PM kiểu easy hơn nhiều Công à. VD: var loadbalancer = cdk.lb(…) Minh Luân Trần2:27 PM lát có nói về cdktf không luôn vậy mấy bro Sa Pham2:29 PM cho em hỏi là nếu như này thì ở trong code mình có gọi đc thông tin của infras ko ?

Ví dụ tạo db aurora, xong trong code mình import cái CDK để lấy connection string tới DB ? Cuong Quach Chi2:30 PM cái Sa hỏi giống “data source” của TF nhỉ Trinh Nguyen2:32 PM CDKtf của Luân kìa nam cxn2:32 PM session sau không có gì hết =)) ĐẠI ĐẶNG VĂN2:32 PM =))) Minh Luân Trần2:32 PM ngon lành :D Sa Pham2:34 PM cái CDKTF thì provider có phải làm gì ko nhỉ? ví dụ bên em phát triển provider cho TF thì có cần thay đổi gì ko để làm việc đc với CDK? hay do nothing :D Trinh Nguyen2:34 PM do nothing Sa Pham2:34 PM xịn Trinh Nguyen2:34 PM cdktf gen ra tf script thôi Minh Luân Trần2:35 PM cdk thì only cho aws thôi nhỉ, còn private hay custom thì cdktf =))) Trinh Nguyen2:35 PM Dùng CDKTF thì làm multicloud Quang Minh Phạm2:37 PM cả 2 bạn ơi =))) Minh Luân Trần2:40 PM em love teraform nhưng ghét python thì sao :1)) Sa Pham2:41 PM phát triển cái CDK riêng cho ngôn ngữ mình yêu thích Cuong Quach Chi2:41 PM nếu mốt CDK phát triển ngon rồi, thì làm sao implement CDK vào quản lý TF code đang có nhỉ :3 . Có vẻ pain in ass :o nam cxn2:42 PM bấm nút trên giao diện cho kẻ mạnh mà, terraform làm gì Sa Pham2:42 PM terraform destroy → deploy a new one Minh Luân Trần2:42 PM em thấy thì cdk generate TF thôi import của TF vẫn còn đó mà :D Cuong Quach Chi2:43 PM đi import lại thì khá là pain in ass again :v hy vọng Hashicorp có plan strategy support migrate hoặc implement integration Minh Luân Trần2:45 PM thôi thì kêu customer ngưng xài vài bữa :D đập đi xây lại Quang Minh Phạm2:45 PM mình có 1 câu hỏi về IaC mà cụ thể là về phần provision như terraform hay cdk ở trên. Thật ra là để tiếp cận với IaC provision này thì khá mất thời gian và cũng tốn nhân lực. Vậy thì IaC trong việc provisioning sẽ có ý nghĩa với các công ty thế nào khi phần lớn các công ty vừa và nhỏ có hạ tầng không reuse nhiều, hầu hết mỗi thứ chỉ tạo 1 vài lần và cứ thế chạy chứ cũng không có thay đổi quá nhiều. Mình thấy IaC provisioning thì có vẻ phù hợp hơn (effort tìm hiểu < lợi ích mang lại) với các công Cuong Quach Chi2:45 PM

You2:46 PM anh em post câu hỏi nhé :-) Quang Minh Phạm2:46 PM (tiếp) với các công ty dạng outsource hoặc chuyên về hạ tầng hơn là các công ty product bt nam cxn2:46 PM @Quang Minh Phạm tí e chém về vấn đề này với bác :)) Trinh Nguyen2:46 PM Chuẩn ĐẠI ĐẶNG VĂN2:47 PM Ngon cá :v Trinh Nguyen2:47 PM Chủ đề hiện tại: Cloud Dev Kit Minh Luân Trần2:47 PM hôm nay là ngày của TF :))) Quang Minh Phạm2:48 PM @nam cxn: waiting for you Minh Luân Trần2:51 PM cho em hỏi là cái cdk này cuối cùng là tạo CFN stack phải không? hay ở trên chỉ là ví dụ thôi? ĐẠI ĐẶNG VĂN2:56 PM A @ Luân : Chắc mình hỏi sau anh nha, nốt câu hỏi này ae chuyển sang session mới rồi ạ ạ. Minh Luân Trần2:57 PM ok @Đại Cuong Quach Chi2:58 PM ok cám ơn Quang Trinh Nguyen3:00 PM LOL Quang Phương3:00 PM bat mic Công Hà Minh3:06 PM Các bác cho em hỏi chút, cái teraform này có support AutoScalingGroup cho OpenStack như thằng Heat AutoScalingGroup không nhỉ? Sa Pham3:07 PM có nhé Công à ko =)) dùng với B*Cloud thì có :v Công Hà Minh3:07 PM -_- You3:09 PM Phương Quang share slides cho bọn mình nhé. Trinh Nguyen3:16 PM :D You3:17 PM Quang Minh Phạm2:45 PM mình có 1 câu hỏi về IaC mà cụ thể là về phần provision như terraform hay cdk ở trên. Thật ra là để tiếp cận với IaC provision này thì khá mất thời gian và cũng tốn nhân lực. Vậy thì IaC trong việc provisioning sẽ có ý nghĩa với các công ty thế nào khi phần lớn các công ty vừa và nhỏ có hạ tầng không reuse nhiều, hầu hết mỗi thứ chỉ tạo 1 vài lần và cứ thế chạy chứ cũng không có thay đổi quá nhiều. Mình thấy IaC provisioning thì có vẻ phù hợp hơn (effort tìm hiểu < lợi ích Quang Minh Phạm3:18 PM với các công ty dạng outsource hoặc chuyên về hạ tầng hơn là các công ty product bt Trinh Nguyen3:19 PM @Son Vu check Q&A Son Vu Anh3:21 PM à để bạn ấy trả lời trước nhé, nếu tôi có góp ý tôi rep luôn sau đó cũng đc lương hữu tuấn3:26 PM cái này phải để red hat trả lời :D Trinh Nguyen3:26 PM LOL kien bui3:29 PM 1 công ty chuyên nghiệp lắm mới có thể có plan hay môi trường chuẩn và ít thay dổi ạ ĐẠI ĐẶNG VĂN3:30 PM IaC có thể opensource, các cty khác tái sử dụng chắc ok mà :D lương hữu tuấn3:31 PM Đây, redhat trả lời nhé:

Legacy change management processes are commonly ignored, bypassed, or overruled by people who need to get things done. Organizations that are more successful in enforcing these processes are increasingly seeing themselves outrun by more technically nimble competitors. Legacy change management approaches struggle to cope with the pace of change offered by cloud and automation. But there is still a need to cope with the ever-growing, continuously changing landscape of sy Thảo Nguyễn Văn3:31 PM Cảm ơn Nam Huy Võ Trung3:31 PM a Nam xịn quá vỗ tay vỗ tay nam cxn3:31 PM lolz ve nha di 2 ban :P Quang Minh Phạm3:31 PM yeah thank ae, vì mình cũng có 1 thời gian làm TF, thấy công nhận là fancy, sáng đến up hạ tầng lên, chiều về down hết xuống để tiết kiệm chi phí =))). nhưng thế mới thấy là mất nhiều thời gian để triển khai các module đấy thật =))) Huy Võ Trung3:31 PM 2021 Open infra tổ chức ở SG thoai Minh Luân Trần3:32 PM +1 SG =)))) Huy Võ Trung3:32 PM +12 +2SG Mạnh Lê Đức3:32 PM +1 SG lương hữu tuấn3:32 PM cái IAS ấy các ông, các ông phải dùng một thời gian mới thâys được TOC nó giảm như thế nào Nguyễn Anh Dũng3:33 PM Các speaker có thể share luôn slide luôn cho mọi người đc ko Trinh Nguyen3:33 PM Sau chương trình mình sẽ tổng hợp nha Nguyễn Anh Dũng3:33 PM Thanks Quang Phương3:37 PM @Quang Minh Phạm đấy là use-case mình có thể nghĩ dùng CDK đấy a ^^ , vừa programming familiar vừa tập trung vào phần business logic Anh Tuấn3:37 PM chắc sắp tới sẽ quan tâm nhiều tới cdk hơn :) Son Vu Anh3:38 PM IAS là gì vậy a Tuấn lương hữu tuấn3:39 PM IAC ông ei, tôi viết nhanh quá nên bị nhầm :P Vu TRAN3:39 PM Meeting có record để xem lại không mọi người nhỉ ? Trinh Nguyen3:39 PM không bạn ơi nam cxn3:39 PM continuous delivery hay la continuous development Trinh Nguyen3:40 PM sáng tháng sau mình sẽ tìm cách nhé Vũ nam cxn3:40 PM phải bản trả phí mới có record a TRình ĐẠI ĐẶNG VĂN3:41 PM Em tưởng có jenkins X rồi :D Trinh Nguyen3:41 PM uhm, chắc lần sau mình setup máy tính rồi record màn hình Nam ơi lương hữu tuấn3:41 PM dùng Openshift có cloud native CI/CD các ông nhé :D Anh Tuấn3:42 PM dùng CI tool native với cloud provider nhé :D Vu TRAN3:42 PM Ok cảm ơn anh Trình Son Vu Anh3:42 PM e công nhận, ko phải dùng IaC thì cost cao lên mà nó có lợi ích tương lai Cuong Nguyen Viet3:43 PM DroneCI ko thấy có trong bxh nhỉ Son Vu Anh3:43 PM nhưng e vẫn không hiểu lắm, nếu cty ko có ai quản lý infra, cứ để mn thay đổi tay tự do thì hơi ảo, dù ko dùng IaC Huy Võ Trung3:43 PM Jenkins thấy xài nhiều nhất mà :D lương hữu tuấn3:43 PM cái IaC đó: nó chú làm system cũ nhé, xong h chuyển cloud, xong bị áp cái tư tưởng cũ, đâm ra mấy cái infra bị manage theo tư duy cũ, mấy cái policy thông qua các cấp để đc cấp infra vô cùng phức tạp cho nên move sang IaC nó giamr thiểu những cái manual mà nó ko liên quan đến tech nữa Thành Lâm3:44 PM argo CD thấy đang lên cực mạnh :v lương hữu tuấn3:44 PM mà mấy cái manual này nó mơis khó để quản lý Quang Minh Phạm3:44 PM argoCD ahihi Anh Tuấn3:45 PM dùng spinnake đi cho nó khó :)) Quang Minh Phạm3:45 PM argoCD đang xxx với weave để đẻ ra argo flux =))) Minh Luân Trần3:45 PM thảm hoạ spin nắc cơ :D Quang Minh Phạm3:45 PM thôi spinaker đao to quá tay cầm ko có nổi =))) Anh Tuấn3:45 PM spinnaker và envoy là thấy 2 thằng configuration khó vl lương hữu tuấn3:46 PM Hay lăms: Spinnakẻ dính vào hẹo lúc nào hem biết nam cxn3:47 PM 1 cty trong top 3 ecommerce to to ở vn đang xài spinneaker :d Quang Minh Phạm3:48 PM =)) đúng zồi vì nó to đó bác chứ cty nhỏ xài giống dao mổ trâu lắm =))) lương hữu tuấn3:48 PM trc tớ làm cái project ở Nokia, bọn tớ deloy nhẹ cái spinnaker trong cho nó biến luôn :D Trinh Nguyen3:49 PM cty nhỏ xài Jenkins simple thôi, kết hợp mấy cli tool -> cloud native vô tư simple Minh Luân Trần3:49 PM jenkins + helm :D Quang Minh Phạm3:49 PM simple là gitlab ci (vừa quản lý code vừa ci cd ko phải cài thêm gì Trinh Nguyen3:49 PM +1 Mạnh Lê Đức3:49 PM gitlabci + helm =))) Anh Tuấn3:49 PM chuẩn bro, thôi em quay lại gitlab ci Quang Minh Phạm3:49 PM căng tý thì gitlab ci + argo Thang Man3:51 PM How to master X in one week Huy Võ Trung3:51 PM :))) me too Thang Man3:53 PM slide đẹp :D Trinh Nguyen3:54 PM Halloween Bùi Đăng Chung3:57 PM Spot instance chứ nhỉ? Minh Luân Trần3:58 PM j4f: hotpot nghe thèm lẩu quá :D Thang Man3:58 PM có tool CD nào cho K8s mà có thể clean up unused resource một cách đáng tin cậy không mọi người? thấy ArgoCD có tính năng này nhưng thấy status=beta Anh Tuấn3:58 PM terraform destroy :)) Quang Minh Phạm3:59 PM unused resource như là gì? Thang Man3:59 PM https://argoproj.github.io/argo-cd/user-guide/orphaned-resources/ Trinh Nguyen4:00 PM orphaned resources Quang Phương4:00 PM clean resources viết script interval auto check sẽ tốt hơn Quang Minh Phạm4:00 PM em xài helm trên argo, mỗi lần thay đổi nếu có resource bị xóa khỏi nó thì đã được tự clean roài :-? còn trò orphan kia thì ko tín lắm Mạnh Lê Đức4:01 PM mình có share slide sau meeting không các bác nhỉ ? Trinh Nguyen4:01 PM Có nha Mạnh xong BQT sẽ tổng hợp và gửi link trên FB group nha Mạnh Lê Đức4:02 PM thanks BQT :D về nghiên cứu dần :v Quang Minh Phạm4:02 PM theo em biết là buildkit đã được tích hợp vào docker build từ v18.06, vậy thì nó có thêm nhiều lợi ích để mà cần phải setup riên gko nam cxn4:03 PM @Huy Võ Trung thắc mắc gì hỏi đi e Quang Phương4:03 PM hotsopt nghe ten cung hay ma :D Thang Man4:03 PM @Quang Minh Pham: oh, nếu là gitops style thì là kiểu nếu một manifest file bị deleted khỏi repo thì resources trong file này cũng cần bị xóa khỏi cluster Le Vinh Vo4:03 PM Krew Quang Phương4:04 PM (like) Quang Minh Phạm4:04 PM @Thang Man, đúng rồi bác, nhưng bác không nên quản lý riêng yaml, mà nên dùng thằng ví dụ helm để quản lý thì hơn Thành Lâm4:04 PM Có cách nào tối ưu được cái quá trình build Images trên gitlab CI ko a ơi... em build trên server vật lý mất 3p nhưng build bằng runner (docker hoặc shell ) thì mất tới gần 10p, mặc dù đã dùng overlay2 và tối giảm các layer trên dockerfile Mạnh Lê Đức4:04 PM chắc bác nói prune-unused plugin phải không https://krew.sigs.k8s.io/plugins/ nam cxn4:05 PM theo bạn CD là continuous delivery hay la continuous development ? Anh Tuấn4:05 PM @namcxn: cả 2 nhé bạn Minh Luân Trần4:05 PM delivery or deployment chứ nhỉ Le Vinh Vo4:05 PM Kustomize Kpt Helm Sa Pham4:05 PM @Mạnh có vẻ ko phải cái krew mà a Vinh nhắc Quang Minh Phạm4:05 PM cái thứ 2 là buildpack nó cũng được viết cho dev không chuyên docker lắm, kiểu setup sẵn các thứ ấy, còn nếu mình viết dc docker file xịn thì em nghĩ ko cần lắm nhỉ (buildpack của heroku, nên dc thiết kế để mọi dev đều có thể dùng được) Le Vinh Vo4:06 PM https://krew.sigs.k8s.io/plugins/ Gogo far away4:07 PM @namcnx cho mình xin slide nhe Bùi Đăng Chung4:07 PM Build ci/cd thì rất tốt rồi, tuy nhiên mình làm việc thì thấy anh em developer muốn test code trên pc. Anh em có kinh nghiệm nào cho vụ đó chỉ mình với Cuong Nguyen Viet4:07 PM Cho e hỏi như thế nào thì đc tính là unuse nhỉ Huy Võ Trung4:07 PM có câu hỏi của bạn Thành Lâm kìa a . Thành lâm : Có cách nào tối ưu được cái quá trình build Images trên gitlab CI ko a ơi... em build trên server vật lý mất 3p nhưng build bằng runner (docker hoặc shell ) thì mất tới gần 10p, mặc dù đã dùng overlay2 và tối giảm các layer trên dockerfile Quang Minh Phạm4:07 PM @Thành Lâm: bạn nên chạy docker pull image cũ, rồi docker build cache from image cũ Le Vinh Vo4:08 PM Skafold Trinh Nguyen4:08 PM @Thang: https://codeberg.org/hjacobs/kube-janitor Le Vinh Vo4:08 PM https://www.waypointproject.io/ Bùi Đăng Chung4:09 PM Cảm ơn bạn Vinh Vo Thành Lâm4:09 PM mình có dùng –cache-from để cache từ images cũ …mà có vẻ ko cải thiện được mấy Thang Man4:10 PM @Quang Minh Pham: Helm thấy focus vào app lifecycle mgmt, nên phần update/delete (một phần) resources trong Helm chart nó làm tốt, mình chỉ ko thích templating language của nó, ví dụ muốn check 1 array có empty hay không, dựa vào đó để create resource mà loay hoay mãi ko làm được, cũng có thể mình chưa tìm ra cách :D Quang Minh Phạm4:10 PM @Thành lâm: bạn xem nó đã thực sự cache chưa, và bạn có pull image cũ xuống chưa (cái này quan trọng) nếu cache rồi thì sẽ là học cách tối ưu dockerfile, chứ ko phải chỉ là giảm hết mức layer (làm nó ko cache dc) Quang Minh Phạm4:11 PM - docker pull $IMAGETAG || echo “Building builder from scratch” - > docker build –cache-from $IMAGETAG

  1. t $IMAGETAG -t $IMAGETAG-$CICOMMITSHORTSHA . - docker push $IMAGETAG

Le Vinh Vo4:11 PM https://thenewstack.io/how-to-enable-docker-experimental-features-and-encrypt-your-login-credentials/ Thang Man4:11 PM mình vào trễ nên ko coi phần trình bày về CI, không biết mobile build iOS, Android thì mọi người có recommend nào không Sa Pham4:12 PM go build thỉnh thoảng có project em thấy cũng lâu mà :D nam cxn4:12 PM go làm gì bằng java :D Quang Minh Phạm4:13 PM go module giờ cache xịn rồi mà các bác =))) chia 2 layer ra cache 1 cái cho module 1 cái cho app là dc Sa Pham4:13 PM có ông ở cty em phải đổi máy khác để build golang =)) trước build trên con máy cũ bị đơ Cuong Nguyen Viet4:13 PM Go nhanh hơn java chứ Le Vinh Vo4:14 PM Circus CI Mạnh Lê Đức4:14 PM vì mình dùng runner trên k8s bằng dind image nên với Dockerfile multi-stage thấy không hiệu quả lắm, không biết có cách nào cải thiện không nhỉ Le Vinh Vo4:14 PM https://cirrus-ci.org/ Thang Man4:15 PM đang tính thử cái Google Firebase cho mobile build, hoặc AWS DeviceFarm lương hữu tuấn4:15 PM giờ bảo anh em K8s re-write k8s bằng java thì thấy ngay go vs java Bang Nguyen4:15 PM anh có thể so sánh nhanh giữa kustomize và helm dựa trên kinh nghiệm sử dụng không? Quang Minh Phạm4:15 PM @mạnh Lê đức: bọn mình cũng xài multistage + dind, thì tạo ra 2 image riêng cho builder và runner, sau đó lần sau thì pull lại rồi cache from, nhanh vồn luôn Thang Man4:15 PM thank @Le Vinh Vo Quang Minh Phạm4:17 PM @mạnh lê đức: full không che đoạn build của em: - docker pull $IMAGETAGBUILDER || echo “Building builder from scratch” - docker pull $IMAGETAG || echo “Building runtime from scratch” - > docker build –target=builder –cache-from $IMAGETAGBUILDER -t $IMAGETAGBUILDER -t $IMAGETAGBUILDER-$CICOMMITSHORTSHA . - >

docker build
--cache-from $IMAGE_TAG 
--cache-from $IMAGE_TAG_BUILDER
-t $IMAGE_TAG
-t $IMAGE_TAG-$CI_COMMIT_SHORT_SHA .

- docker push $IMAGETAGBUILDER Le Vinh Vo4:18 PM https://github.com/GoogleContainerTools/kpt lương hữu tuấn4:18 PM Fan google chính thống đây rồi :P Le Vinh Vo4:18 PM gRPC Thang Man4:18 PM nếu chơi kiểu autoscaling CI, các agents create/delete on-demand liên tục, thì việc cache image layers khi chạy các step trong Dockerfile là tại local disk của agent là không thực hiện được. Uber có cái Makisu, mọi người có thể thử, vì nó lưu cache ở private registry (e.g. ECR, GCR, v.v..) Le Vinh Vo4:18 PM Kubernetse Cuong Nguyen Viet4:18 PM Cloud build luôn cho 99% a Anh Tuấn Đường4:19 PM Vào trễ, có link slide ko anh ơi :D ĐẠI ĐẶNG VĂN4:19 PM Slide chia sẻ sau trên group a nha Anh Tuấn Đường4:20 PM dạ uki thanks anh Trinh Nguyen4:21 PM :)) cái gì? Mạnh Lê Đức4:21 PM @Quang Minh Phạm: thanks bác =))) chắc phải tách mới được rồi :v Quang Phương4:21 PM :D Cuong Nguyen Viet4:21 PM Có cách nào check lỗi leak memory image trên CI ko a Quang Minh Phạm4:23 PM mình thấy giờ việc của CI tool rút lại khá ít khi mà mấy cái task build đã cho hết vào docker build, thì tức là tool CI giờ chỉ cần chạy dc bash docker build là ok, vậy thì tác dụng của những tool CI phức tạp sẽ không có mấy nữa Anh Tuấn Đường4:23 PM mới học thì chắc dùng jenkins thui lâu lâu học travis nữa Thang Man4:23 PM cty nhỏ chơi GitHub Actions :D, bên mình dùng nó chạy mấy bước check code lint là điều kiện để trước khi PR được merge, chạy nhiều thì cũng hit free limits Mạnh Lê Đức4:23 PM VNG team this team that nữa mà =)) Quoc-Bao Nguyen4:23 PM VNG nhiều team mà :D Anh Tuấn4:23 PM mới học xài gitlab ci thôi :)) Quoc-Bao Nguyen4:23 PM Có team this team that :D Sa Pham4:24 PM FPT dùng jenkins. chắc FPT là cty to rồi Trinh Nguyen4:24 PM =)) Mạnh Lê Đức4:24 PM @Quoc-Bao Nguyen còn làm đó k =)))) Tran Thanh4:24 PM FPT bé Quoc-Bao Nguyen4:24 PM Dạ còn :D Tran Thanh4:24 PM Toàn theo dự án ko ah Cuong Nguyen Viet4:24 PM Bên e dùng droneCI cho 50 service thấy cũng khá ổn Mạnh Lê Đức4:25 PM e cũng thấy Spinnaker cũng ổn =))) bỏ vài tuần đọc docs với apply cũng ok :v nhiều tính năng =))) không thiếu món Quang A. Nguyen4:26 PM những tool CI thường phải để file yaml pipeline trong code (exam Github Actions có .github/workflows) – anh có kinh nghiệm gì để quản lý file này cho công ty có nhiều service repository (~200) ko ạ? ví dụ cần update 1 step trong pipeline thì làm thế nào ạ? Quang Minh Phạm4:31 PM các bạn có để ý tới vấn đề phân chia quyền của dev trong các pipeline CI/CD không? ví dụ dev có thể sửa config pipeline để in ra variable chả hạn Thang Man4:31 PM https://github.community/t/being-dry-centralized-workflows/16548/3

Chưa hỗ trợ centralize các file workflows của github actions bên mình xài GoCD cho cả CI/CD, có hỗ trợ centralize toàn bộ pipelines của dev lẫn infra Quang A. Nguyen4:33 PM Gịthub Actions ko có include như Gitlab :( Thang Man4:33 PM ngoài ra còn từng xài Gitlab, Jenkins, DroneCI. nói chung mỗi team họ có opinion, requirement, và background quen xài tool nào đó, nên mất thời gian công sức để chuẩn hóa hay ép xài.

Concourse CI </code>

6. Documentation

[OLD] Quickstart

Following 2 scoops book.

  • Setup Virtualenv and start virtualenv virtualenv pjs_env # not need no-site-update. Self contained env by default source …
    • Boilerplace project folder with cookiescutter

    pip install cookiecutter cookiecutter https://github.com/pydanny/cookiecutter-django -c 1.8.7 #1.9.7

“c” option with branch string to checkout. The project will be checked out in ~/.cookiecutter and copy to the location. Follow instruction on https://github.com/pydanny/cookiecutter-django/tree/1.8.7. The project root is ready to be pushed to git.

You can now run the usual Django migrate and runserver commands:

$ python manage.py migrate
$ python manage.py runserver

At this point you can take a break from setup and start getting to know the files in the project.

But if you want to go further with setup, read on.

(Note: the following sections still need to be revised) Setting Up Env Vars for Production

Cookiecutter Django uses the excellent django-environ package, which includes a DATABASE_URL environment variable to simplify database configuration in your Django settings.

Rename env.example to .env to begin updating the file with your own environment variables. To add your database, define DATABASE_URL and add it to the .env file, as shown below:

DATABASE_URL="postgres://<pg_user_name>:<pg_user_password>@127.0.0.1:<pg_port>/<pg_database_name>"

Setup your email backend

django-allauth sends an email to verify users (and superusers) after signup and login (if they are still not verified). To send email you need to configure your email backend

In development you can (optionally) use MailHog for email testing. MailHog is built with Go so there are no dependencies. To use MailHog:

Download the latest release for your operating system
Rename the executable to mailhog and copy it to the root of your project directory
Make sure it is executable (e.g. chmod +x mailhog)
Execute mailhog from the root of your project in a new terminal window (e.g. ./mailhog)
All emails generated from your django app can be seen on http://127.0.0.1:8025/

Alternatively simply output emails to the console via:

  EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

In production basic email configuration is setup to send emails with Mailgun

Testing Mailhog

  • Register user account
  • email with confirmation url is output in console
  • Click the url!!!

Live reloading and Sass CSS compilation

If you’d like to take advantage of live reloading and Sass / Compass CSS compilation you can do so

Django-cms

Project structure details

Multiple settings files

Instead of having one settings.py le, with this setup you have a settings/ directory containing your settings les. is directory will typically contain something like the following:

settings/
  __init__.py
  base.py
  local.py
  staging.py
  test.py
  production.py

base.py Settings common to all instances of the project.

local.py This is the settings file that you use when you're working on the project locally. Local development-specific settings include DEBUG mode, log level, and activation of developer tools like django-debug-toolbar. Developers sometimes name this file dev.py.

staging.py Staging version for running a semi-private version of the site on a production server. This is

test.py Settings for running tests including test runners, in-memory database definitions, and log settings.

production.py where managers and clients should be looking before your work is moved to production. This is the settings file used by your live production server(s). That is, the server(s) that host the real live website. This file contains production-level settings only. It is sometimes called prod.py.

Each settings module should have its own corresponding requirements file.

Multiple Files With Continuous Integration Servers

You’ll also want to have a ci.py module containing that server’s settings. Similarly, if it’s a large project and you have other special-purpose servers, you might have custom settings les for each of them.

To start the Python interactive interpreter with Django, using your settings/local.py settings file:

  python manage.py shell --settings=twoscoops.settings.local
  

To run the local development server with your settings/local.py settings file:

  python manage.py runserver --settings=twoscoops.settings.local
  

A great alternative to using the –settings command line option everywhere is to set the DJANGO SETTINGS MODULE and PYTHONPATH environment variable to your desired settings module path. You’d have to set DJANGO SETTINGS MODULE to the corresponding settings module for each environment, of course.

For those with a more comprehensive understanding of virtualenv, another alternative is to set DJANGO SETTINGS MODULE and PYTHONPATH in the postactivate script. en, once the virtualenv is activated, you can just type python from anywhere and import those values into your project. is also means that typing django-admin.py at the command-line works without the –settings option.

https://docs.djangoproject.com/en/1.9/topics/settings/

Separate Configuration From Code

Here are the bene ts of using environment variables for secret keys:

  • Keeping secrets out of settings allows you to store every settings le in version control without

hesitation. All of your Python code really should be stored in version control, including your settings.

  • Instead of each developer maintaining an easily-outdated, copy-and-pasted version of the

local settings.py.example le for their own development purposes, everyone shares the same version-controlled settings/local.py .

  • System administrators can rapidly deploy the project without having to modify les containing

Python code.

  • Most platforms-as-a-service recommend the use of environment variables for con guration

and have built-in features for setting and managing them.

Before you begin setting environment variables, you should have the following:

  • A way to manage the secret information you are going to store.
  • A good understanding of how bash works with environment variables on servers, or a willing-

ness to have your project hosted by a platform-as-a-service. For more information, see http://2scoops.co/wikipedia-env-variable.

Environment Variables Do Not Work With Apache

How to Set Environment Variables Locally

On Mac and many Linux distributions that use bash for the shell, one can add lines like the following to the end of a .bashrc, .bash pro le, or .pro le. When dealing with multiple projects using the same API but with different keys, you can also place these at the end of your virtualenv’s bin/activate script:

  $ export SOME_SECRET_KEY=1c3-cr3am-15-yummy
  $ export AUDREY_FREEZER_KEY=y34h-r1ght-d0nt-t0uch-my-1c3-cr34m
  

How to Set Environment Variables in Production

If you’re using your own servers, your exact practices will differ depending on the tools you’re us- ing and the complexity of your setup. For the simplest 1-server setup for test projects, you can set the environment variables manually. But if you’re using scripts or tools for automated server provi- sioning and deployment, your approach may be more complex. Check the documentation for your deployment tools for more information. If your Django project is deployed via a platform-as-a-service, check the documentation for spe- ci c instructions. We’ve included Heroku instructions here so that you can see that it’s similar for platform-as-a-service options. On Heroku, you set environment variables with the following command, executed from your devel- opment machine:

  $ heroku config:set SOME_SECRET_KEY=1c3-cr3am-15-yummy

To see how you access environment variables from the Python side, open up a new Python prompt and type:

  >>> import os
  >>> os.environ["SOME_SECRET_KEY"]
  "1c3-cr3am-15-yummy"
  

To access environment variables from one of your settings les, you can do something like this:

  # Top of settings/production.py
  import os
  SOME_SECRET_KEY = os.environ["SOME_SECRET_KEY"]

Handling Missing Secret Key Exceptions

In the above implementation, if the SECRET KEY isn’t available, it will throw a KeyError , making it impossible to start the project. at’s great, but a KeyError doesn’t tell you that much about what’s actually wrong. Without a more helpful error message, this can be hard to debug, especially under the pressure of deploying to servers while users are waiting and your ice cream is melting. Here’s a useful code snippet that makes it easier to troubleshoot those missing environment variables. If you’re using our recommended environment variable secrets approach, you’ll want to add this to your settings/base.py file:

# settings/base.py
import os
# Normally you should not import ANYTHING from Django directly
# into your settings, but ImproperlyConfigured is an exception.
from django.core.exceptions import ImproperlyConfigured

def get_env_variable(var_name):
"""Get the environment variable or return exception."""
  try:
    return os.environ[var_name]
  except KeyError:
    error_msg = "Set the {} environment variable".format(var_name)
    raise ImproperlyConfigured(error_msg)

Then, in any of your settings les, you can load secret keys from environment variables as follows:

  SOME_SECRET_KEY = get_env_variable("SOME_SECRET_KEY")

WARNING: Don't Import Django Components Into Settings Modules

TIP: Using django-admin.py Instead of manage.py

The official Django documentation says that you should use django-admin.py rather than manage.py when working with multiple settings files: https://docs.djangoproject.com/en/1.8/ref/django-admin/ at being said, if you’re struggling with django-admin.py, it’s perfectly okay to develop and launch your site running it with manage.py.

When You Can't Use Environment Variables

The problem with using environment variables to store secrets is that it doesn’t always work. The most common scenario for this is when using Apache for serving HTTP, but this also happens even in Nginx-based environments where operations wants to do things in a particular way. When this occurs, rather than going back to the local settings anti-pattern, we advocate using non-executable les kept out of version control in a method we like to call the secrets le pattern. To implement the secrets le pattern, follow these three steps:

  • Create a secrets le using the con guration format of choice, be it JSON, Con g, YAML, or even XML.
  • Add a secrets loader ( JSON-powered example below) to manage the secrets in a cohesive, explicit manner.
  • Add the secrets le name to the .gitignore or .hgignore.

    Using JSON Files

Our preference is to use shallow JSON les. e JSON format has the advantage of being the format of choice for various Python and non-Python tools. To use the JSON format, first create a secrets.json file:

{
"FILENAME": "secrets.json",
"SECRET_KEY": "I've got a secret!", .
"DATABASES_HOST": "127.0.0.1",
"PORT": "5432"
}

To use the secrets.json file, add the following code to your base settings module.

# settings/base.py
import json
# Normally you should not import ANYTHING from Django directly
# into your settings, but ImproperlyConfigured is an exception.
from django.core.exceptions import ImproperlyConfigured
# JSON-based secrets module
with open("secrets.json") as f:
secrets = json.loads(f.read())
.
def get_secret(setting, secrets=secrets):
"""Get the secret variable or return explicit exception."""
try:
return secrets[setting]
except KeyError:
error_msg = "Set the {0} environment variable".format(setting)
raise ImproperlyConfigured(error_msg)
SECRET_KEY = get_secret("SECRET_KEY")

Using Config, YAML, and XML File Formats

While we prefer the forced simplicity of shallow JSON, others might prefer other le formats. We’ll leave it up to the reader to create additional get secret() alternatives that work with these for- mats. Just remember to be familiar with things like yaml.safe load() and XML bombs. See section 26.9, ‘Defend Against Python Code Injection Attacks.’

Using Multiple Requirements Files

To follow this pattern, recommended to us by Jeff Triplett, rst create a requirements/ directory in the <repository root>. en create ‘.txt’ les that match the contents of your settings directory. results should look something like:

requirements/
base.txt
local.txt
staging.txt
production.txt

In the base.txt le, place the dependencies used in all environments. For example, you might have something like the following in there:

Django==1.8.0
psycopg2==2.6
djangorestframework==3.1.1

Your local.txt le should have dependencies used for local development, such as:

  1. r base.txt # includes the base.txt requirements file
coverage==3.7.1
django-debug-toolbar==1.3.0

The needs of a continuous integration server might prompt the following for a ci.txt le:

  1. r base.txt # includes the base.txt requirements file
coverage==3.7.1
django-jenkins==0.16.4

Production installations should be close to what is used in other locations, so production.txt com- monly just calls base.txt:

  1. r base.txt # includes the base.txt requirements file

Add Package and Version Number to Your Requirements

Using Multiple Requirements Files With Platforms as a Service (PaaS)

Handling File Paths in Settings

Don’t hardcode your paths!

If you really want to set your BASE DIR with the Python standard library’s os.path library, though, this is one way to do it in a way that will account for paths:

# At the top of settings/base.py
from os.path import join, abspath, dirname

here = lambda *dirs: join(abspath(dirname(__file__)), *dirs)
BASE_DIR = here("..", "..")
root = lambda *dirs: join(abspath(BASE_DIR), *dirs)
# Configuring MEDIA_ROOT
MEDIA_ROOT = root("media")
# Configuring STATIC_ROOT
STATIC_ROOT = root("collected_static")
# Additional locations of static files
STATICFILES_DIRS = (
.
root("assets"),
)
# Configuring TEMPLATE_DIRS
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
DIRS = (root("templates"),)
},
]

Source env.local.source

export POSTGRES_PASSWORD=maxopw
export POSTGRES_USER=maxo

export DJANGO_ADMIN_URL=
export DJANGO_SETTINGS_MODULE=config.settings.local
#export DJANGO_SECRET_KEY=di60zn#ni9_j)8ek-u+zdcw=0()4=@iq48d3m6ereq1287wdl3
#export DJANGO_ALLOWED_HOSTS=.example.com

export DJANGO_AWS_ACCESS_KEY_ID=
export DJANGO_AWS_SECRET_ACCESS_KEY=
export DJANGO_AWS_STORAGE_BUCKET_NAME=
export DJANGO_MAILGUN_API_KEY=
export DJANGO_MAILGUN_SERVER_NAME=
export DJANGO_SERVER_EMAIL=
export DJANGO_SECURE_SSL_REDIRECT=False
export DJANGO_SENTRY_DSN=

export NEW_RELIC_LICENSE_KEY

export DJANGO_OPBEAT_ORGANIZATION_ID
export DJANGO_OPBEAT_APP_ID
export DJANGO_OPBEAT_SECRET_TOKEN
source env.local.source

Database

Database

Create postgres database maxoshop_project with user maxo/maxopw.

Edit config.settings.common.py

# DATABASE CONFIGURATION
# ------------------------------------------------------------------------------
# See: https://docs.djangoproject.com/en/dev/ref/settings/#databases
DATABASES = { 
    'default': env.db("DATABASE_URL", default="psql://maxo:maxopw@127.0.0.1:5432/maxoshop_project"),
}
DATABASES['default']['ATOMIC_REQUESTS'] = True
1)
(( Trinh Nguyen2:40 PM xài typescript Minh Luân Trần2:41 PM em chỉ biết typescript là đuôi ts thôi đó, khổ :

Navigation