前幾天的打底,
把 Gitlab、Jenkins 建好,
但是仍然少了最重要的主角,
要部署的服務本身,
今天我們終於要建立一個 Portal 來部署囉,
以下 Portal 建立會以 Python Django 為例,
挑選 Python Django 是因為大多數 Web 服務器都不是用 Python 所撰寫,
需要另外設定接口才能夠讓服務器和 Python 溝通,
再加上 Python 有提供虛擬環境(Virtual Environment),
在套件管理上不需要仰賴全域的配置,個人是覺得 Python 2 和 Python 3 有 Break 才會有這功能
很少在建置陽春的環境時,
就需要做這麼麻煩的設定,
因此很適合當作教學使用,
已經會建立專案的,
可以跳過專案建立步驟去看 EC2 和 WSGI 的配置,
如果兩個都會的,
估計手動部署到 EC2 也不成問題,
可以直接跳過今天的教學休息一天。
前天 EP07 時
我們已經建立一個 portal 的 repository
接下來我們就需要再次進到 vagrant 的 project 中
把 code check out 下來
cd /vagrant_data/project/
git clone git@你的IP:ithome-ironman-2021/portal.git
cd portal
git branch develop
git push -u origin develop
當時我們挑選的 Ubuntu 20.04
已經內建 python3
不過保險起見
還是先確認版本和位置
python --version
whereis python 3
如果不幸你的 Linux 版本比較舊
都沒有預先安裝 Python 3
建議可參考 在Linux上安装Python 3
如果我們有一個以上的 Python 專案
此時我們就需要思考每個環境的 Python 版本和套件版本是否一致
我們在 /vagrant_data 中建立新的資料夾 venv
以便可以在 vagrant 建立的虛擬機械內外
都可以操作
cd /vagrant_data/
sudo mkdir vevn
cd venv
sudo apt-get install python3-pip
安裝好後輸入 pip3 指令
查看指令是否可以正常運作
pip3 --version
sudo pip3 install virtualenv
先查看 virtualenv 的位置後
pip3 show virtualenv
在用 python 執行建立 virtualenv
建立名為 ithome-ironman-portal 的虛擬環境
python3 /home/vagrant/.local/lib/python3.8/site-packages/virtualenv ithome-ironman-portal
使用 source 或是 . ithome-ironman-portal/bin/activate
都可以啟動虛擬環境
source ithome-ironman-portal/bin/activate
啟動後就可以看到 console 前會出現 (ithome-ironman-portal) 的字樣
如果是使用 windows
無法正常啟用虛擬環境
或是啟用後安裝套件都會把全域的套件版本蓋掉的
可以參考這篇
有可能是因為在 windows 上的 path 設定了 python 的路徑
導致 virtualenv 運作有問題
想知道是否有正常設置
還可以執行下列語法
pip3 list
一個乾淨的 virtualenv 環境
在初始化後應該只會看到兩三個基本套件
python -m pip install Django
其實只要下 django-admin startproject portal
就可以產生一個專案
不過因為我們專案是從 Gitlab 上 clone 下來的
又因為起專案時
只能指定空的資料夾
因此我們只能先在一個地方起專案後
再將專案內的東西搬移到 project 底下的 portal 裏面
cd /vagrant_data
django-admin startproject portal
sudo cp -R /vagrant_data/portal/*.* /vagrant_data/project/portal
sudo cp -R /vagrant_data/portal/portal/ /vagrant_data/project/portal/
sudo rm -rf /vagrant_data/portal/
cd /vagrant_data/project/portal/
接下來只要啟動
server 就可以運作了
python manage.py runserver 0.0.0.0:8000
但我們使用瀏覽器依舊無法看到啟動的 server
此時別慌
電腦沒有壞,安裝過程也正常
是因為我們在虛擬機械裡面起 server
但是 port 沒有轉發到虛擬機械外面
此時我們需要修改 Vagrantfile
在 config.vm.box 下方
新增一個 port 轉發的設定
.
.
.
config.vm.box = "ubuntu/focal64"
config.vm.network "forwarded_port", guest: 8000, host: 8000
.
.
.
重啟 vagrant 不需要下 vagrant halt 再 vagrant up
vagrant reload
source /vagrant_data/venv/ithome-ironman-portal/bin/activate
cd /vagrant_data/project/portal
python manage.py runserver 0.0.0.0:8000
關於 vagrant 內為什麼要 runserver 0.0.0.0:8000
大家可參考「Connection Reset when port forwarding with Vagrant」和「Connection Reset when port forwarding with Vagrant」的討論
剛剛我們建立虛擬環境
而且還安裝套件都只存在於本機
但是實際上多人協作
不會把 python 和虛擬環境進版控
而是會將套件版本記錄起來進版控
在 python 中的套件管理工具是 pip
而記錄這些套件的檔案則是 requirements.txt
只要下個指令就可以把目前虛擬環境中的套件記錄起來
pip freeze > requirements.txt
# Django #
*.log
*.pot
*.pyc
__pycache__
db.sqlite3
media
# Backup files #
*.bak
# If you are using PyCharm #
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/dictionaries
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.xml
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/gradle.xml
.idea/**/libraries
*.iws /out/
# Python #
*.py[cod]
*$py.class
# Distribution / packaging
.Python build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
.pytest_cache/
nosetests.xml
coverage.xml
*.cover
.hypothesis/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery
celerybeat-schedule.*
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# mkdocs documentation
/site
# mypy
.mypy_cache/
# Sublime Text #
*.tmlanguage.cache
*.tmPreferences.cache
*.stTheme.cache
*.sublime-workspace
*.sublime-project
# sftp configuration file
sftp-config.json
# Package control specific files Package
Control.last-run
Control.ca-list
Control.ca-bundle
Control.system-ca-bundle
GitHub.sublime-settings
# Visual Studio Code #
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history
settings.py 修改 DATABASE
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': '',
'USER': '',
'PASSWORD': '',
'HOST': '',
'PORT': '5432'
}
}
requirements.txt 新增一條
psycopg2==2.8.6
已經連續教好幾天要怎麼建置 EC2 了
不會還要教吧?
沒關係,送佛上西天
我們直接附上解答
讓你把 EC2、security group、security group rule 都配置好
比較特別的是
這裡有特別加入 port 3128
因為聽說 pip install 是走 3128
resource "aws_security_group" "ithome_ironman_portal" {
name = "ithome-ironman-portal"
description = "It is used for ithome ironman 2021 portal."
vpc_id = data.aws_vpc.default.id
tags = { Name = "ithome ironman 2021" }
revoke_rules_on_delete = null
}
resource "aws_security_group_rule" "ithome_ironman_igress_22" {
type = "ingress"
from_port = 22
to_port = 22
cidr_blocks = [var.personal_cidr,]
protocol = "tcp"
security_group_id = aws_security_group.ithome_ironman_portal.id
}
resource "aws_security_group_rule" "ithome_ironman_egress_22" {
type = "egress"
from_port = 22
to_port = 22
cidr_blocks = [var.personal_cidr,]
protocol = "tcp"
security_group_id = aws_security_group.ithome_ironman_portal.id
}
resource "aws_security_group_rule" "ithome_ironman_igress_80" {
type = "ingress"
from_port = 80
to_port = 80
cidr_blocks = [var.personal_cidr,]
protocol = "tcp"
security_group_id = aws_security_group.ithome_ironman_portal.id
}
resource "aws_security_group_rule" "ithome_ironman_egress_80" {
type = "egress"
from_port = 80
to_port = 80
cidr_blocks = ["0.0.0.0/0",]
protocol = "tcp"
security_group_id = aws_security_group.ithome_ironman_portal.id
}
resource "aws_security_group_rule" "ithome_ironman_igress_443" {
type = "ingress"
from_port = 443
to_port = 443
cidr_blocks = [var.personal_cidr,]
protocol = "tcp"
security_group_id = aws_security_group.ithome_ironman_portal.id
}
resource "aws_security_group_rule" "ithome_ironman_egress_443" {
type = "egress"
from_port = 443
to_port = 443
cidr_blocks = ["0.0.0.0/0",]
protocol = "tcp"
security_group_id = aws_security_group.ithome_ironman_portal.id
}
resource "aws_security_group_rule" "ithome_ironman_ingress_3128" {
type = "ingress"
from_port = 3128
to_port = 3128
cidr_blocks = ["0.0.0.0/0",]
protocol = "tcp"
security_group_id = aws_security_group.ithome_ironman_portal.id
}
resource "aws_security_group_rule" "ithome_ironman_egress_3128" {
type = "egress"
from_port = 3128
to_port = 3128
cidr_blocks = ["0.0.0.0/0",]
protocol = "tcp"
security_group_id = aws_security_group.ithome_ironman_portal.id
}
resource "tls_private_key" "ithome_ironman_portal" {
algorithm = "RSA"
rsa_bits = 4096
}
resource "aws_key_pair" "ithome_ironman_portal" {
key_name = "portal"
public_key = tls_private_key.ithome_ironman_portal.public_key_openssh
}
resource "local_file" "ithome_ironman_portal" {
content = tls_private_key.ithome_ironman_portal.private_key_pem
filename = format("%s.pem", aws_key_pair.ithome_ironman_portal.key_name)
}
resource "aws_instance" "ithome_ironman_portla" {
ami = data.aws_ami.ubuntu.id
instance_type = "t3.small"
subnet_id = sort(data.aws_subnet_ids.subnet_ids.ids)[0]
key_name = aws_key_pair.ithome_ironman_portal.key_name
vpc_security_group_ids = [ aws_security_group.ithome_ironman_portal.id ]
disable_api_termination = false
ebs_optimized = true
hibernation = false
tags = {
Name = "ithome ironman 2021 portal"
Usage = "portal"
Creator = "Terraform"
}
root_block_device {
delete_on_termination = true
encrypted = false
throughput = 0
volume_size = 9
volume_type = "gp2"
tags = {
Name = "ithome ironman 2021 portal"
Attached = "ithome ironman 2021 portal"
}
}
}
sudo chmod 400 portal.pem
ssh -i "portal.pem" ubuntu@你的HOST
sudo apt-get update
sudo apt-get upgrdae -y
sudo apt-get install apache2
sudo apt-get install python3 python3-virtualenv python3-pip libpq-dev python-dev
sudo mkdir /var/www/venv
如果不更改擁有者
或是沒使用 chmod 更改資料夾/檔案權限
等等在進行安裝 mod_wsgi 時會失敗
sudo chown -R ubuntu /var/www/venv
pip3 show virtualenv
sudo python3 /usr/lib/python3/dist-packages/virtualenv /var/www/venv/portal
source /var/www/venv/portal/bin/activate
pip install -vvv mod_wsgi
將 module 位置複製起來
等等在 confige apache 時會用上
pip show mod-wsgi
剛剛查到的 wsgi 模組位置
會用在 LoadModule wsgi_module 上
需要將路徑替換掉 你的路徑/mod_wsgi/server/mod_wsgi-py38.cpython-38-x86_64-linux-gnu.so
apache 的 conf 檔位於 /etc/apache2/apache2.conf 中
WSGIPythonHome 是設定剛剛 virtualenv 的路徑
WSGIPythonPath 則是設定專案的根目錄
在 conf 底下加相對應的參數大致如下
ServerName localhost
Alias /static/ /var/www/portal/static
<Directory /var/www/portal/static>
Require all granted
</Directory>
LoadModule wsgi_module "/var/www/venv/portal/lib/python3.8/site-packages/mod_wsgi/server/mod_wsgi-py38.cpython-38-x86_64-linux-gnu.so"
WSGIPythonHome /var/www/venv/portal
WSGIPythonPath /var/www/portal
WSGIScriptAlias / /var/www/portal/portal/wsgi.py
<Directory /var/www/portal/portal>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
如果直接將資料夾封存
會遇到一個問題
就是
git archive --format=tar.gz --output ./portal.tar.gz HEAD
scp -i "/vagrant_data/project/terraform/stage/portal.pem" ./portal.tar.gz ubuntu@你的HOST:~/portal.tar.gz
ssh -i "/vagrant_data/project/terraform/stage/portal.pem" ubuntu@你的HOST
sudo mkdir /var/www/portal
sudo mv ~/portal.tar.gz /var/www/portal
cd /var/www/portal
sudo tar zxvf portal.tar.gz
sudo chmod 755 -R /var/www/portal
安裝套件前
記得要先啟動虛擬環境source /var/www/venv/portal/bin/activate
pip install -r /var/www/portal/requirements.txt
sudo service apache2 restart
如果重啟遇到這問題
表示已經離成功不遠了
這是 Django 的一個安全機制
需要在 settings.py 的 ALLOWED_HOSTS 裡面加 EC2 的 IP(或是連入的HOST NAME)
加入後再 restart apache2
就可以正常啟動囉
參考資料: