記一次使用python-alpine鏡像部署Django項目排錯經歷

背景


       在對公司的Django項目進行容器化的過程中,生產環境上出現了一個問題:客戶在前臺使用產品時有部分請求會返回403狀態碼,刷新一下後就又訪問成功了。後端開發人員在進行排查時發現返回403狀態碼的原因是客戶攜帶的token過期了,但客戶是幾分鐘之前才登陸的。在諮詢後端工程師對token校驗的邏輯後發現,非正常的請求客戶的token時間比passport服務器上的時間晚了8小時,即部分後端服務器上的程序所使用的時區是UTC,而passport服務器是CST,導致校驗不通過。

      由於該項目是由我剛剛完成容器化並部署至生產環境上的,所以在nginx裏我只將10%的請求轉發至k8s集羣,這也是爲何客戶刷新一下頁面又訪問正常的原因。

排查與解決


      經過檢查容器服務器的時區後,/etc/timezone的內容確認是Asia/Shanghai,而且Django的配置文件中也是將時區設置爲Asia/Shanghai,跑在服務器上的程序返回的時間也是正常的,所以初步猜想是容器的環境導致的問題。容器的基礎鏡像是python:3.7-alpine,所以我編寫了一個非常簡單的django配置文件分別在centos服務器和python-alpine服務器上進行測試,配置文件如下:

cat settings.py
USE_TZ = False
TIME_ZONE = 'Asia/Shanghai'
SECRET_KEY = 'hello'

   配置文件比較簡單,use_tz字段禁止使用Django默認的時區,time_zone字段配置時區,secret_key配置一個密碼(隨便寫,別爲空就行),接下來使用“控制變量法”進行排查:

1、use_tz = True

#centos:
>>> import os
>>> os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
>>> from django.utils import timezone
>>> d1 = timezone.now()
>>> print(d1)
2020-06-04 10:58:28.405656+00:00                 #非北京時間
>>>  

#python-alpine:
>>> import os
>>> os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
>>> from django.utils import timezone
>>> d1 = timezone.now()
>>> print(d1)
2020-06-04 10:59:30.649517+00:00         #非北京時間,但與centos的時區相同
>>> 

2、use_tz=False, time_zone='Asia/Shanghai'

#centos:
>>> import os
>>> os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
>>> from django.utils import timezone
>>> d1 = timezone.now()
>>> print(d1)
2020-06-04 18:51:15.040756                 #取到的時間正常
>>>  

#python-alpine:
>>> import os
>>> os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
>>> from django.utils import timezone
>>> d1 = timezone.now()
>>> print(d1)
2020-06-04 10:55:19.288442            #該時間不是北京時間
>>> 

   以上兩種情況表明,在使用默認時區情況下二者所取到的時間並無差別,都使用的是UTC時間,但當指定時區後,在alpine容器裏似乎並沒有生效,但是我的容器裏的/etc/timezone和/etc/localtime的內容與centos的配置一模一樣,出現這種情況是不是表明Django不是從這兩個文件中的一個取的時間呢?我將容器和centos機器的timezone和localtime文件刪除後得到的結果跟之前兩種情況測試完全一致,這表明我們之前的猜想是對的:Django程序沒有從這兩個文件中取時間。

    由於我本人之前對Django不是特別熟悉,查閱了官方文檔後發現,在Linux服務器上部署Django程序時,時區的選擇是從/usr/share/zoneinfo目錄下查找的,而查找的路徑則是/usr/share/zoneinfo/settings.TIME_ZONE。這時我忽然想起來在製作容器鏡像時我在做完容器的時區設定後將tzdata刪除了(爲了保障容器鏡像儘可能小),Dockerfile文件內容如下:

cat Dockerfile
FROM python:3.7-alpine

WORKDIR /app

RUN apk add tzdata && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
    && echo "Asia/Shanghai" > /etc/timezone \
    && apk del tzdata

COPY . /app
RUN pipenv install --deploy  --system --ignore-pipfile \
    && rm -fr ~/.cache/pip* \
    && rm -fr /tmp \
    && mkdir /app/logs \
    && touch /app/logs/access.log \
    && touch /app/logs/error.log

   在測試集羣的容器裏將鏡像進行更新後,複測問題已經解決,而且訪問日誌的時間也一併調整爲北京時間,問題圓滿解決:

啓示


    1、 在面對問題時需要先保障業務恢復,在本次問題出現時先將容器提供的服務從正式環境中摘離出來,保障後續客戶使用正常,然後再進行排查解決;

    2、在將項目進行容器化之前一定要對項目框架熟悉一些,需要跟開發人員和測試人員多多交流,儘量規避一些可能出現的問題,在將容器化項目部署到生產環境時一定要與之前的環境實行藍綠部署或者金絲雀部署等灰度發佈規則,出現較大問題時能夠第一時間回退,當容器化項目迭代一段時間後再考慮將將老環境摘離生產;

   3、遇到問題時有了猜想及排查思路就要儘快動手驗證,多進行驗證才能儘快找到突破口。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章