<address id="tl19n"></address>
      <address id="tl19n"><nobr id="tl19n"></nobr></address>

        <address id="tl19n"></address>

          <address id="tl19n"></address>
          <form id="tl19n"></form>

              首頁 > 上網技巧 > 使用 Fabric 自動化部署

              使用 Fabric 自動化部署

              時間:2022-01-17 13:05 作者:QQ地帶 我要評論

              在上一篇教程中,我們通過手工方式將代碼部署到了服務器。整個過程涉及到十幾條命令,輸了 N 個字符。一旦我們本地的代碼有更新,整個過程又得重復來一遍,這將變得非常繁瑣。
               
              使用 Fabric 可以在服務器中自動執行命令。因為整個代碼部署過程都是相同的,只要我們用 Fabric 寫好部署腳本,以后就可以通過運行腳本自動完成部署了。
               
              首先在本地安裝 Fabric:
               
              $ pipenv install fabric --dev
              因為 Fabric 只需在本地使用,因此使用 --dev 選項,讓 Pipenv 將 Fabric 依賴寫到 dev-packages 配置下,線上環境就不會安裝 Fabric。
               
              部署過程回顧
              在寫 Fabric 腳本之前,先來回顧一下當我們在本地開發環境下更新了代碼后,在服務器上的整個部署過程。
               
              遠程連接服務器。
              進入項目根目錄,從遠程倉庫拉取最新的代碼。
              如果項目引入了新的依賴,需要執行 pipenv install --deploy --ignore-pipfile 安裝最新依賴。
              如果修改或新增了項目靜態文件,需要執行 pipenv run python manage.py collectstatic 收集靜態文件。
              如果數據庫發生了變化,需要執行 pipenv run python manage.py migrate 遷移數據庫。
              重啟 Nginx 和 Gunicorn 使改動生效。
              整個過程就是這樣,把每一步操作翻譯成 Fabric 對應的腳本代碼,這樣一個自動化部署腳本就完成了。
               
              完善項目配置
              分離 settings 文件
              為了安全,線上環境我們將 debug 改為了 False,但開發環境要改為 True,改來改去將很麻煩。此外,django 的 SECRET_KEY 是很私密的配置,django 的很多安全機制都依賴它,如果不慎泄露,網站將面臨巨大安全風險,像我們現在這樣直接寫在配置文件中,萬一不小心公開了源代碼,SECRET_KEY 就會直接泄露,好的實踐是將這個值寫入環境變量,通過從環境變量取這個值。
               
              解決以上問題的一個方案就是拆分 settings.py 文件,不同環境對應不同的 settings 文件,django 在啟動時會從環境變量中讀取 DJANGO_SETTINGS_MODULE 的值,以這個值指定的文件作為應用的最終配置。
               
              我們來把 settings.py 拆分,首先在 blogproject 目錄下新建一個 Python 包,名為 settings,然后創建一個 common.py,用于存放通用配置,local.py 存放開發環境的配置,production.py 存放線上環境的配置:
               
              blogproject\
                  settings\
                      __init__.py
                      local.py
                      production.py
                  settings.py
              將 settings.py 文件中的內容全部復制到 common.py 里,并將 SECRET_KEY、DEBUG、ALLOWED_HOSTS 這些配置移到 local.py 和 production.py 中(common.py 中這些項可以刪除)。
               
              開發環境的配置 local.py 內容如下:
               
              from .common import *
               
              SECRET_KEY = 'development-secret-key'
              DEBUG = True
              ALLOWED_HOSTS = ['*']
              線上環境的配置:
               
              from .common import *
               
              SECRET_KEY = os.environ['DJANGO_SECRET_KEY']
              DEBUG = False
              ALLOWED_HOSTS = ['hellodjango-blog-tutorial-demo.zmrenwu.com']
              注意這里我們在頂部使用 from .common import * 將全部配置從 common.py 導入,然后根據環境的不同,在下面進行配置覆蓋。
               
              線上環境和開發環境不同的是,為了安全,DEBUG 模式被關閉,SECRET_KEY 從環境變量獲取,ALLOWED_HOSTS 設置了允許的 HTTP HOSTS(具體作用見后面的講解)。
               
              以上操作完成后,一定記得刪除 settings.py。
               
              現在我們有了兩套配置,一套是 local.py,一套是 production.py,那么啟動項目時,django 怎么知道我們使用了哪套配置呢?答案是在運行 manage.py 腳本時,django 默認幫我們指定了。在使用 python manage.py 執行命令時,django 可以接收一個 --settings-module 的參數,用于指定執行命令時,項目使用的配置文件,如果參數未顯示指定,django 會從環境變量 DJANGO_SETTINGS_MODULE 里獲取?吹 manage.py 的源碼:
               
              def main():
                  os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'blogproject.settings')
                  try:
                      from django.core.management import execute_from_command_line
                  except ImportError as exc:
                      raise ImportError(
                          "Couldn't import Django. Are you sure it's installed and "
                          "available on your PYTHONPATH environment variable? Did you "
                          "forget to activate a virtual environment?"
                      ) from exc
                  execute_from_command_line(sys.argv)
              可以看到這個 main 函數,第一行的 setdefault 為我們設置了環境變量 DJANGO_SETTINGS_MODULE 的值,這句代碼的作用是,如果當前環境中 DJANGO_SETTINGS_MODULE 的值沒有被設置,就將其設置為 blogproject.settings,所以我們使用 python manage.py 執行命令時,django 默認為我們使用了 settings.py 這個配置。
               
              所以我們可以通過設置環境變量,來指定 django 使用的配置文件。
               
              對于 manage.py,通常在開發環境下執行,因此將這里的 DJANGO_SETTINGS_MODULE 的值改為 blogproject.settings.local,這樣運行開發服務器時 django 會加載 blogproject/settings/local.py 這個配置文件。
               
              另外看到 wsgi.py 文件中,這個文件中有一個 application,是在線上環境時 Gunicorn 加載運行的,將這里面的 DJANGO_SETTINGS_MODULE 改為 blogproject.settings.production
               
              這樣,在使用 manage.py 執行命令時,加載的是 local.py 的設置,而使用 gunicorn 運行項目時,使用的是 production.py 的設置。
               
              修改 BASE_DIR 配置項
              還有需要注意的一點,看到存放通用配置的 common.py 文件,里面有一個配置項為:
               
              BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
              這個 BASE_DIR 指向項目根目錄,其獲取方式為根據所在的配置文件向上回溯,找到項目根目錄。因為此前的目錄結構為 HelloDjango-blog-tutorial/blogproject/settings.py,因此向上回溯 2 層就到達項目根目錄。而現在目錄結構變為 HelloDjango-blog-tutorial/blogproject/settings/common.py,需向上回溯 3 層才到達項目根目錄,因此需將 BASE_DIR 進行一個簡單修改,修改如下:
               
              BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
              即再在外面包一層 os.path.dirname,再向上回退一層,到達項目根目錄。
               
              設置 Supervisor 環境變量
              此外,由于線上環境配置中的 secret_key 從環境變量獲取,因此我們改一下 supervisor 的配置,將環境變量導入,打開 supervisor 的配置文件 ~/etc/supervisor/conf.d/hellodjango-blog-tutorial.ini,添加環境變量的配置語句:
               
              environment=DJANGO_SECRET_KEY=2pe8eih8oah2_2z1=7f84bzme7^bwuto7y&f(#@rgd9ux9mp-3
              因為此前可能將代碼傳過公開的代碼倉庫,所以最好把線上使用的 SECRET_KEY換一下。這個網站可以自動生成 SECRET_KEY:Django Secret Key Generator。
               
              保存配置,然后要執行 update 命令更新配置。
               
              $ supervisorctl -c ~/etc/supervisord.conf update
              編寫 Fabric 腳本
              一切準備工作均已就緒,現在就來使用 Fabric 編寫自動部署腳本。
               
              Fabric 腳本通常位于 fabfile.py 文件里,因此先在項目根目錄下建一個 fabfile.py 文件。
               
              根據上述過程編寫的腳本代碼如下:
               
              from fabric import task
              from invoke import Responder
              from _credentials import github_username, github_password
               
               
              def _get_github_auth_responders():
                  """
                  返回 GitHub 用戶名密碼自動填充器
                  """
                  username_responder = Responder(
                      pattern="Username for 'https://github.com':",
                      response='{}\n'.format(github_username)
                  )
                  password_responder = Responder(
                      pattern="Password for 'https://{}@github.com':".format(github_username),
                      response='{}\n'.format(github_password)
                  )
                  return [username_responder, password_responder]
               
               
              @task()
              def deploy(c):
                  supervisor_conf_path = '~/etc/'
                  supervisor_program_name = 'hellodjango-blog-tutorial'
               
                  project_root_path = '~/apps/HelloDjango-blog-tutorial/'
               
                  # 先停止應用
                  with c.cd(supervisor_conf_path):
                      cmd = 'supervisorctl stop {}'.format(supervisor_program_name)
                      c.run(cmd)
               
                  # 進入項目根目錄,從 Git 拉取最新代碼
                  with c.cd(project_root_path):
                      cmd = 'git pull'
                      responders = _get_github_auth_responders()
                      c.run(cmd, watchers=responders)
               
                  # 安裝依賴,遷移數據庫,收集靜態文件
                  with c.cd(project_root_path):
                      c.run('pipenv install --deploy --ignore-pipfile')
                      c.run('pipenv run python manage.py migrate')
                      c.run('pipenv run python collectstatic --noinput')
               
                  # 重新啟動應用
                  with c.cd(supervisor_conf_path):
                      cmd = 'supervisorctl start {}'.format(supervisor_program_name)
                      c.run(cmd)
              來分析一下部署代碼。
               
              deploy 函數為部署過程的入口,加上 task 裝飾器將其標注為一個 fabric 任務。
               
              然后定義了一些項目相關的變量,主要是應用相關代碼和配置所在服務器的路徑。
               
              deploy 函數被調用時會傳入一個 c 參數,這個參數的值是 Fabric 在連接服務器時創建的 ssh 客戶端實例,使用這個實例可以在服務器上運行相關命令。
               
              接著就是執行一系列部署命令了,進入某個目錄使用 ssh 客戶端實例的 cd 方法,運行命令使用 run 方法。
               
              需要注意的是,每次 ssh 客戶端實例執行新的命令是無狀態的,即每次都會在服務器根目錄執行新的命令,而不是在上一次執行的命令所在目錄,所以要在同一個目錄下連續執行多條命令,需要使用 with c.cd 上下文管理器。
               
              最后,如果服務器沒有加入代碼倉庫的信任列表,運行 git pull 一般會要求輸入密碼。我們代碼托管使用了 GitHub,所以寫了一個 GitHub 賬戶密碼響應器,一旦 Fabric 檢測到需要輸入 GitHub 賬戶密碼,就會調用這個響應器,自動填寫賬戶密碼。
               
              由于響應器從 _credentials.py 模塊導入敏感信息,因此在 fabfile.py 同級目錄新建一個 _credentials.py文件,寫上 GitHub 的用戶名和密碼:
               
              github_username = 'your-github-username'
              github_password = 'your-github-password'
              當然,這個文件包含賬戶密碼等敏感信息,所以一定記得將這個文件加入 .gitignore 文件,將其排除在版本控制系統之外,別一不小心提交了公開倉庫,導致個人 GitHub 賬戶泄露。
               
              執行 Fabric 自動部署腳本
              進入 fabfile.py 文件所在的目錄,用 fab 命令運行這個腳本文件(將 server_ip 換為你線上服務器的 ip 地址):
               
              pipenv run fab -H server_ip --prompt-for-login-password -p deploy
              這時 Fabric 會自動檢測到 fabfile.py 腳本中的 deploy 函數并運行,輸入服務器登錄密碼后回車,然后你會看到命令行輸出了一系列字符串,最后看到部署完畢的消息。
               
              如果腳本運行中出錯,檢查一下命令行輸出的錯誤信息,修復問題后重新運行腳本即可。以后當你在本地開發完相關功能后,只需要執行這一個腳本文件,就可以自動把最新代碼部署到服務器了。

              標簽: Fabric
              頂一下
              (0)
              0%
              踩一下
              (0)
              0%

              Google提供的廣告

              国产古代一级a毛片,国产成人午夜在线直播,write.as 当众老师
                <address id="tl19n"></address>
                  <address id="tl19n"><nobr id="tl19n"></nobr></address>

                    <address id="tl19n"></address>

                      <address id="tl19n"></address>
                      <form id="tl19n"></form>