自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

精益求精!如何讓你的Python項(xiàng)目從自動(dòng)化中受益

開發(fā) 后端 自動(dòng)化
無(wú)論你的項(xiàng)目是用于開發(fā)Web應(yīng)用,處理數(shù)據(jù)科學(xué)問(wèn)題還是AI,使用配置良好的CI / CD,可在開發(fā)中調(diào)試且針對(duì)生產(chǎn)環(huán)境進(jìn)行了優(yōu)化的Docker鏡像,或一些其它的代碼質(zhì)量工具,都能讓你受益。本文將告訴你該如何把它們加入Python項(xiàng)目中!

本文轉(zhuǎn)載自公眾號(hào)“讀芯術(shù)”(ID:AI_Discovery)

無(wú)論你的項(xiàng)目是用于開發(fā)Web應(yīng)用,處理數(shù)據(jù)科學(xué)問(wèn)題還是AI,使用配置良好的CI / CD,可在開發(fā)中調(diào)試且針對(duì)生產(chǎn)環(huán)境進(jìn)行了優(yōu)化的Docker鏡像,或一些其它的代碼質(zhì)量工具,都能讓你受益。

本文將告訴你該如何把它們加入Python項(xiàng)目中!

這是我的倉(cāng)庫(kù),其中包含完整的源代碼和文檔:https://github.com/MartinHeinz/python-project-blueprint

[[323308]]

用于開發(fā)的可調(diào)試Docker容器

有些人不喜歡Docker,因?yàn)槿萜骺赡芎茈y調(diào)試,或者因?yàn)樗鼈兊溺R像需要很長(zhǎng)時(shí)間才能構(gòu)建。因此,讓我們從構(gòu)建用于開發(fā)的理想鏡像開始,它能夠快速構(gòu)建且易于調(diào)試。

為了使鏡像易于調(diào)試,需要基礎(chǔ)鏡像,其中包括調(diào)試時(shí)可能需要的所有工具,例如bash,vim,netcat,wget,cat,find,grep等。

python:3.8.1-buster似乎是這一任務(wù)的理想選擇。它在默認(rèn)情況下包含許多工具,我們可以很容易地安裝所有缺少的東西。這個(gè)基本鏡像非常厚重,但這并不重要,因?yàn)榇藭r(shí)它將僅用于開發(fā)。

你可能已經(jīng)注意到,我選擇了非常具體的鏡像:鎖定了Python版本和Debian版本。這是故意的,因?yàn)槲覀兿M畲蟪潭鹊販p少由更新的,可能不兼容的Python或Debian版本引起“損壞”的可能性。

精益求精!如何讓你的Python項(xiàng)目從自動(dòng)化中受益
圖源:techcrunch

可以使用基于Alpine的鏡像作為替代。但是,這可能會(huì)引起一些問(wèn)題,因?yàn)樗褂胢usllibc而不是Python依賴的glibc。因此,如果決定選擇此配置,請(qǐng)記住這一點(diǎn)。

至于構(gòu)建的速度,我們將利用多階段構(gòu)建以便緩存盡可能多的層。這樣,就可以避免下載例如gcc的依賴項(xiàng)和工具以及(requirements.txt中的)應(yīng)用程序所需的所有庫(kù)。

因?yàn)闊o(wú)法將下載和安裝這些工具所需的步驟緩存到最終的運(yùn)行程序鏡像中,我們將使用前面提到的python:3.8.1-buster創(chuàng)建自定義基本鏡像,該鏡像將包含需要的所有工具,從而進(jìn)一步提升處理速度。

說(shuō)了這么多,來(lái)看看Dockerfile:

  1. # dev.Dockerfile 
  2.              FROMpython:3.8.1-buster AS builder 
  3.              RUN apt-get update&& apt-get install -y --no-install-recommends --yes python3-venv gcclibpython3-dev && \ 
  4.                 python3 -m venv /venv && \ 
  5.                  /venv/bin/pip install --upgradepip 
  6.              
  7.              FROM builder ASbuilder-venv 
  8.              
  9.              COPYrequirements.txt /requirements.txt 
  10.              RUN /venv/bin/pipinstall -r /requirements.txt 
  11.              
  12.              FROM builder-venv AStester 
  13.              
  14.              COPY . /app 
  15.              WORKDIR /app 
  16.              RUN/venv/bin/pytest 
  17.              
  18.              FROMmartinheinz/python-3.8.1-buster-tools:latest AS runner 
  19.              COPY --from=tester/venv /venv 
  20.              COPY --from=tester/app /app 
  21.              
  22.              WORKDIR /app 
  23.              
  24.              ENTRYPOINT ["/venv/bin/python3", "-m", "blueprint"] 
  25.              USER 1001 
  26.              
  27.              LABEL name={NAME} 
  28.              LABELversion={VERSION} 

從上面的文檔可以看到我們將創(chuàng)建3個(gè)中間鏡像,然后創(chuàng)建最終的運(yùn)行鏡像。第一個(gè)鏡像被稱為builder,它會(huì)下載構(gòu)建最終應(yīng)用程序所需的所有必需庫(kù),其中包括gcc和Python虛擬環(huán)境。安裝完成后,它還會(huì)創(chuàng)建實(shí)際的虛擬環(huán)境以供下一個(gè)鏡像使用。

接著是builder-venv鏡像,該鏡像將依賴項(xiàng)列表(requirements.txt)復(fù)制到鏡像中,然后進(jìn)行安裝。緩存需要此中間鏡像,因?yàn)閮H在requirements.txt更改時(shí)才會(huì)安裝庫(kù),否則僅使用緩存。

在創(chuàng)建最終鏡像之前,首先要針對(duì)應(yīng)用程序運(yùn)行測(cè)試。這就是tester鏡像做的工作。我們將源代碼復(fù)制到鏡像中并運(yùn)行測(cè)試。如果通過(guò)了,程序就會(huì)運(yùn)行至runner。

對(duì)于runner鏡像,我們使用的是自定義鏡像,其中包括普通Debian鏡像中不存在的一些額外功能,例如vim或netcat。你可以在Docker Hub上的這里找到此鏡像,還可以通過(guò)這里在base.Dockerfile中檢驗(yàn)這個(gè)非常簡(jiǎn)單的Dockerfile。

因此,在最終鏡像中的工作有這些:首先復(fù)制虛擬環(huán)境,該環(huán)境保留了tester鏡像中所有已安裝的依賴項(xiàng),接下來(lái)復(fù)制經(jīng)過(guò)測(cè)試的應(yīng)用程序。

現(xiàn)在,鏡像已經(jīng)擁有了所有源,移至應(yīng)用程序所在的目錄設(shè)置ENTRYPOINT,以便在鏡像啟動(dòng)時(shí)運(yùn)行應(yīng)用程序。出于安全原因?qū)SER設(shè)置為1001,因?yàn)樽罴褜?shí)踐告訴我們,永遠(yuǎn)不要在root用戶下運(yùn)行容器。

最后2行設(shè)置鏡像的標(biāo)簽。當(dāng)使用make 命令指向構(gòu)建并運(yùn)行時(shí),這些將被替換或填充,這一點(diǎn)稍后我們會(huì)看到。

為產(chǎn)品優(yōu)化的Docker容器

談及產(chǎn)品級(jí)鏡像時(shí),我們想確保它們小巧,安全且快速。我個(gè)人最喜歡的是Distroless項(xiàng)目中的Python鏡像。那么什么是Distroless?

可以這樣形容它:在理想的世界中,每個(gè)人都將使用FROM scratch作為其基本鏡像(即空鏡像)來(lái)構(gòu)建其鏡像。

但這不是大多數(shù)人想要做的,因?yàn)樗箪o態(tài)連接二進(jìn)制文件等。這就是Distroless發(fā)揮作用的地方了,它是為每個(gè)人設(shè)計(jì)的FROM scratch。

Distroless是由Google制作的一組鏡像,包含應(yīng)用所需的最低要求,這意味著沒(méi)有殼(shell),程序包管理器或任何其他工具會(huì)使鏡像膨脹并給安全掃描器(例如CVE)造成信號(hào)噪聲,從而使其變得更難建立規(guī)則。

知道了要解決的問(wèn)題,讓我們看一下生產(chǎn)型Dockerfile ...... 實(shí)際上,在這里不需要做太多更改,只有兩行:

  1. # prod.Dockerfile 
  2.               #  1. Line - Change builder image 
  3.               FROMdebian:buster-slim AS builder 
  4.               #  ... 
  5.               #  17. Line - Switch to Distroless image 
  6.               FROMgcr.io/distroless/python3-debian10 AS runner 
  7.               #  ... Rest of the Dockefile 

需要更改的只是用于構(gòu)建和運(yùn)行應(yīng)用程序的基本鏡像!

但是差別是巨大的:我們的開發(fā)鏡像為1.03GB,而這個(gè)鏡像僅為103MB,這是完全不一樣的!

我知道你會(huì)說(shuō)“但是Alpine可以變得更小”是的,沒(méi)錯(cuò),但是大小的差距并不那么重要。你只會(huì)在下載/上傳鏡像時(shí)注意鏡像的大小,這種情況并不常見。當(dāng)鏡像運(yùn)行時(shí),大小完全不重要。比大小更重要的是安全性,就這一點(diǎn)而言,Distroless肯定具有優(yōu)勢(shì),因?yàn)锳lpine(這是一個(gè)很好的替代)具有許多額外的程序包,可以增加攻擊面。

關(guān)于Distroless值得一提的最后一件事是調(diào)試鏡像。考慮到Distroless不包含任何殼(甚至不包括sh),這使得需要調(diào)試和檢查時(shí)非常棘手。為此,所有Distroless鏡像都有調(diào)試版本。

因此,當(dāng)遇到麻煩時(shí),可以使用debug標(biāo)簽構(gòu)建生產(chǎn)鏡像,并將其部署到常規(guī)鏡像旁邊,在其中執(zhí)行并且進(jìn)行如線程轉(zhuǎn)儲(chǔ)的操作??梢韵襁@樣使用python3鏡像的調(diào)試版本:

  1. docker run --entrypoint=sh -tigcr.io/distroless/python3-debian10:debug 

適用一切情況的單一命令

在準(zhǔn)備好所有Dockerfile后,不妨使用Makefile將其自動(dòng)化吧!要做的第一件事是使用Docker構(gòu)建應(yīng)用程序。因此,為了構(gòu)建開發(fā)鏡像,我們可以執(zhí)行make build-dev命令來(lái)運(yùn)行以下目標(biāo)文件:

  1. # The binary to build (just the basename). 
  2.          MODULE :blueprint 
  3.          
  4.          # Where to push the docker image. 
  5.          REGISTRY ?=docker.pkg.github.com/martinheinz/python-project-blueprint 
  6.          
  7.          IMAGE := $(REGISTRY)/$(MODULE) 
  8.          
  9.          # This version-strategy uses git tagsto set the version string 
  10.          TAG := $(shell git describe --tags--always --dirty) 
  11.          
  12.          build-dev: 
  13.             @echo "\n${BLUE}BuildingDevelopment image with labels:\n" 
  14.             @echo "name: $(MODULE)" 
  15.             @echo "version: $(TAG)${NC}\n" 
  16.             @sed                                 \ 
  17.                 -e's|{NAME}|$(MODULE)|g'        \ 
  18.                -e 's|{VERSION}|$(TAG)|g'        \ 
  19.                dev.Dockerfile | docker build -t $(IMAGE):$(TAG) -f- . 

該目標(biāo)文件首先通過(guò)在dev.Dockerfile的底部用標(biāo)簽替換鏡像的名稱和標(biāo)簽來(lái)構(gòu)建鏡像,該標(biāo)簽是通過(guò)運(yùn)行g(shù)it describe然后運(yùn)行docker build來(lái)創(chuàng)建的。

下一步——使用make build-prod VERSION = 1.0.0構(gòu)建生產(chǎn)版本:

  1. build-prod: 
  2.         @echo "\n${BLUE}Building Productionimage with labels:\n" 
  3.         @echo "name: $(MODULE)" 
  4.         @echo "version: $(VERSION)${NC}\n" 
  5.         @sed                                     \ 
  6.             -e's|{NAME}|$(MODULE)|g'            \ 
  7.            -e 's|{VERSION}|$(VERSION)|g'       \ 
  8.            prod.Dockerfile | docker build -t $(IMAGE):$(VERSION) -f- .. 

這個(gè)與先前的目標(biāo)文件非常相似,但是在1.0.0版本上的示例中,我們將把版本作為參數(shù)傳遞,而不是使用git標(biāo)簽作為版本。

當(dāng)在Docker中運(yùn)行所有內(nèi)容時(shí),有時(shí)需要在Docker中對(duì)其進(jìn)行調(diào)試,為此,有以下目標(biāo)文件:

  1. # Example: make shell CMD="-c 'date> datefile'" 
  2.          shell: build-dev 
  3.             @echo "\n${BLUE}Launching a shellin the containerized build environment...${NC}\n" 
  4.                 @docker run                                                    \ 
  5.                     -ti                                                    \ 
  6.                     --rm                                                   \ 
  7.                     --entrypoint /bin/bash                                  \ 
  8.                     -u $$(id -u):$$(id -g)                                  \ 
  9.                     $(IMAGE):$(TAG)                      \ 
  10.                     $(CMD) 

從上面可以看出,bash覆蓋了入口點(diǎn),而參數(shù)則覆蓋了容器命令。這樣,我們可以像上面的示例那樣直接進(jìn)入容器并進(jìn)行調(diào)試或運(yùn)行一個(gè)關(guān)閉命令。

當(dāng)完成編碼并想將鏡像推送到Docker注冊(cè)表時(shí),可以使用makepush VERSION = 0.0.2。來(lái)看看目標(biāo)文件的功能:

  1. REGISTRY ?=docker.pkg.github.com/martinheinz/python-project-blueprint 
  2.                                        push:build-prod 
  3.                                         @echo"\n${BLUE}Pushing image to GitHub Docker Registry...${NC}\n" 
  4.                                         @dockerpush $(IMAGE):$(VERSION) 

它首先運(yùn)行之前看過(guò)的build-prod文件,然后運(yùn)行docker push。這里假設(shè)已登錄Docker注冊(cè)表,因此在運(yùn)行此注冊(cè)表之前,需要運(yùn)行docker login。

最后一個(gè)目標(biāo)文件用來(lái)清理Docker工件。它使用替換為Dockerfiles的name標(biāo)簽來(lái)過(guò)濾和查找需要?jiǎng)h除的工件:

  1. docker-clean: 
  2.        @docker system prune -f --filter "label=name=$(MODULE)" 

使用GitHub Actions的CI / CD

現(xiàn)在開始使用所有這些方便的make目標(biāo)命令來(lái)設(shè)置CI / CD。我們將使用GitHub Actions和GitHub Package Registry來(lái)構(gòu)建管道(工作)并存儲(chǔ)鏡像。那么這兩個(gè)東西到底是什么呢?

  • Github Actions是可以幫助自動(dòng)化開發(fā)工作流程的作業(yè)/管道??梢允褂盟鼈儊?lái)創(chuàng)建單個(gè)任務(wù),然后將它們組合到自定義的工作流程中,然后在諸如每次推送到倉(cāng)庫(kù)或創(chuàng)建發(fā)行版的時(shí)候執(zhí)行這些工作流程。
  • GitHub Package Registry是與GitHub完全集成的軟件包托管服務(wù)。它可以存儲(chǔ)各種類型的軟件包,例如:Ruby gems或npm軟件包。我們將使用它來(lái)存儲(chǔ)Docker鏡像。
  • 如果你不熟悉GitHub Package Registry,并且想要了解更多相關(guān)信息,可以查看我的博客文章:https://martinheinz.dev/blog/6
[[323310]]
圖源:unsplash

現(xiàn)在,為了使用GitHub Action,需要?jiǎng)?chuàng)建工作流,這些工作流將根據(jù)選擇的觸發(fā)器(例如,推送到倉(cāng)庫(kù))執(zhí)行。這些工作流是YAML文件,位于倉(cāng)庫(kù)中的.github / workflows目錄中:

  1. .github       
  2.        └── workflows         
  3.           ├── build-test.yml           
  4.           └── push.yml 

第一項(xiàng)工作名為build,它通過(guò)運(yùn)行make build-dev命令來(lái)驗(yàn)證是否可以構(gòu)建應(yīng)用程序。但在運(yùn)行它之前,它首先通過(guò)執(zhí)行在GitHub上發(fā)布的名為checkout的操作來(lái)檢索倉(cāng)庫(kù)。

  1. jobs:        
  2.        test:         
  3.          runs-on: ubuntu-latest           
  4.          steps:           
  5.          - uses: actions/checkout@v1           
  6.          - uses: actions/setup-python@v1            
  7.           with:            
  8.              python-version: '3.8'           
  9.          - name: Install Dependencies            
  10.           run: |             
  11.             python -m pip install --upgrade pip               
  12.             pip install -r requirements.txt           
  13.          - name: Run Makefile test            
  14.             run: make test           
  15.          - name: Install Linters           
  16.             run: |              
  17.              pip install pylint               
  18.              pip install flake8               
  19.              pip install bandit           
  20.          - name: Run Linters            
  21.           run: make lint 

第二項(xiàng)工作稍微復(fù)雜一些。它針對(duì)應(yīng)用程序以及3個(gè)linter(代碼質(zhì)量檢查器)運(yùn)行測(cè)試。

與上一項(xiàng)工作相同,我們使用checkout@v1操作獲取源代碼。之后,運(yùn)行另一個(gè)名為setup-python@v1的已發(fā)布操作,該操作幫助設(shè)置了python環(huán)境(你可以在此處找到有關(guān)它的詳細(xì)信息)。

現(xiàn)在有了python環(huán)境,還需要使用pip安裝的requirements.txt中的應(yīng)用程序依賴項(xiàng)。此時(shí)可以繼續(xù)運(yùn)行make test命令,這將觸發(fā)Pytest套件。如果測(cè)試套件通過(guò),將繼續(xù)安裝前面提到的linters,即pylint,flake8和bandit。最后運(yùn)行make lint命令,這將觸發(fā)每個(gè)linter。

這就是構(gòu)建/測(cè)試工作的全部流程,但是應(yīng)該如何推送呢?來(lái)看一下:

  1. on:    
  2.   push:      
  3.     tags:       
  4.      - '*'    
  5.   jobs:    
  6.     push:       
  7.      runs-on: ubuntu-latest        
  8.      steps:        
  9.      - uses: actions/checkout@v1        
  10.      - name: Set env         
  11.       run: echo ::set-envname=RELEASE_VERSION::$(echo ${GITHUB_REF:10})        
  12.      - name: Log intoRegistry         
  13.       run: echo "${{secrets.REGISTRY_TOKEN }}" |  
  14. docker login docker.pkg.github.com -u ${{github.actor }} --password-stdin     
  15.      - name: Push to GitHubPackage Registry         
  16.       run: make pushVERSION=${{ env.RELEASE_VERSION }} 

前4行定義了何時(shí)觸發(fā)這項(xiàng)工作。我們指定僅當(dāng)將標(biāo)簽推送到倉(cāng)庫(kù)時(shí)才開始該工作(*在這種情況下指定標(biāo)簽名稱可以是任何模式),因此不會(huì)在每次推送到倉(cāng)庫(kù)時(shí)都將Docker鏡像推送到GitHub Package Registry,而僅在推送指定應(yīng)用程序新版本的標(biāo)簽時(shí)才推送到GitHubPackage Registry。

現(xiàn)在到了工作的主體,它是從檢索源代碼并將RELEASE_VERSION的環(huán)境變量設(shè)置為推送的git標(biāo)簽開始的。這是通過(guò)GitHub Actions的內(nèi)置:: setenv功能完成的。

接下來(lái),它使用存儲(chǔ)在repository secrets中的REGISTRY_TOKEN登錄到Docker注冊(cè)表,并登錄啟動(dòng)工作流的用戶(github.actor)。最后,在最后一行中,它運(yùn)行push命令,該命令構(gòu)建生產(chǎn)鏡像并將其推送到注冊(cè)表,并以先前推送的git標(biāo)簽作為鏡像標(biāo)簽。

此處可以檢索出完整的代碼清單:

https://github.com/MartinHeinz/python-project-blueprint/tree/master/.github/workflows

使用CodeClimate進(jìn)行代碼質(zhì)量檢查

最后但并非最不重要的一點(diǎn)是,還要使用CodeClimate和SonarCloud來(lái)添加代碼質(zhì)量檢查。這些將與上面展示的test工作一起觸發(fā)。因此,我們?cè)谄渲刑砑訋仔校?/p>

  1. # test, lint... 
  2.            - name: Send report toCodeClimate 
  3.                        run: |             
  4.                          export GIT_BRANCH="${GITHUB_REF/refs\/heads\//}"               
  5.                          curl -Lhttps://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64> ./cc-test-reporter               
  6.                          chmod +x ./cc-test-reporter               
  7.                          ./cc-test-reporter format-coverage -t coverage.py coverage.xml               
  8.                          ./cc-test-reporter upload-coverage -r "${{secrets.CC_TEST_REPORTER_ID }}"                 
  9.                          - name: SonarCloudscanner             
  10.                            uses: sonarsource/sonarcloud-github-action@master             
  11.                            env:            
  12.                               GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}               
  13.                               SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 

從CodeClimate開始,首先導(dǎo)出GIT_BRANCH變量,然后使用GITHUB_REF環(huán)境變量進(jìn)行檢索。其次,下載CodeClimate測(cè)試報(bào)告程序并使其可執(zhí)行。然后,使用它來(lái)格式化由測(cè)試套件生成的覆蓋率報(bào)告,并在最后一行將其發(fā)送到帶有測(cè)試報(bào)告器ID的CodeClimate中,該ID存儲(chǔ)在repository secrets中。

至于SonarCloud,我們需要在倉(cāng)庫(kù)中創(chuàng)建如下所示的sonar-project.properties文件(文件中的值可以在SonarCloud儀表板的右下角找到):

  1. .organization=martinheinz-github 
  2.                          sonar.projectKey=MartinHeinz_python-project-blueprint                         
  3.                              sonar.sources=blueprint 

除此之外,只需使用已有的sonarcloud-github-action就可以幫我們完成所有工作。要做的就是提供2個(gè)令牌:GitHub令牌(默認(rèn)情況下位于倉(cāng)庫(kù)中)和SonarCloud令牌(可從SonarCloud網(wǎng)站獲得)。

注意:有關(guān)如何獲取和設(shè)置所有上述令牌和密鑰的步驟,請(qǐng)參見README文件:

https://github.com/MartinHeinz/python-project-blueprint/blob/master/README.md

[[323311]]
圖源:unsplash

有了上述的工具、配置和代碼,你就可以構(gòu)建和自動(dòng)化下一個(gè)Python項(xiàng)目的方各個(gè)方面了??烊ピ囋嚢?

 

責(zé)任編輯:趙寧寧 來(lái)源: 讀芯術(shù)
相關(guān)推薦

2022-06-26 09:55:00

接口自動(dòng)化項(xiàng)目

2022-07-12 14:31:55

機(jī)器學(xué)習(xí)人工智能工具

2021-10-14 06:52:47

自動(dòng)化開發(fā)環(huán)境

2020-11-25 10:42:57

Python代碼工具

2024-08-02 17:23:12

2019-06-04 08:54:56

Python數(shù)據(jù)驅(qū)動(dòng)腳本

2018-02-10 18:35:09

LinuxAnsible系統(tǒng)管理

2022-12-08 10:55:12

5G倉(cāng)庫(kù)自動(dòng)化

2022-11-04 19:00:00

Python自動(dòng)化

2013-11-27 11:34:43

自動(dòng)化部署Python

2011-03-02 14:15:06

Pureftpd

2020-02-14 20:49:33

設(shè)施管理物聯(lián)網(wǎng)IOT

2018-02-25 19:29:49

自動(dòng)化數(shù)字化IT

2016-11-07 08:40:51

天池腳本自動(dòng)化

2015-02-04 09:17:38

亞馬遜AWS云自動(dòng)化

2024-11-21 15:24:49

2020-03-18 09:23:24

Python數(shù)據(jù)SQL

2024-12-31 09:46:45

2019-11-05 15:40:41

網(wǎng)絡(luò)安全跳槽那些事兒軟件

2019-07-23 23:00:37

物聯(lián)網(wǎng)工業(yè)物聯(lián)網(wǎng)預(yù)測(cè)性維護(hù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)