基於 Docker ,Gogs,Jenkins,Kubernetes 實踐工程源代碼的自動構建和持續集成與部署交付

本期目標 : 基於 Centos 7.6 , 封裝出一個可用於運行 php 項目的開箱即用鏡像
本文不討論 dockerfile 語法 , 並且假設你懂得基本的類unix 操作系統常識並擁有類unix 運行環境 (包括但不限於安裝了mac 或 linux 的實體機 , 類unix虛擬機 , 安裝了 MinGW 或 CygWin 的 windows 機器) , 並且認爲你懂得基本的 docker 操作和有一定的 dockerfile 閱讀能力

準備工作

建立工作目錄

mkdir ~/docker-learn
cd ~/docker-learn

創建Dockerfile

touch Dockerfile

然後拷貝你常用的 nginx.conf 到工作目錄

cp xxx/nginx.conf nginx.conf

封裝基礎鏡像

編輯我們創建好的 Dockerfile

基礎內容

聲明本鏡像繼承自 centos 最新版

FROM centos

安裝 nginx

  • 創建nginx源文件

    由於 centos 倉庫裏是沒有 nginx 的 , 所以我們要自力更新添加nginx的源到 docker 裏
    複製 nginx.org 裏關於 RHEL 源的內容到 nginx.repo 文件

    也可以本地執行以下命令創建 nginx.repo

    sudo tee ./nginx.repo <<-'EOF'
    [nginx-stable]
    name=nginx stable repo
    baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
    gpgcheck=1
    enabled=1
    gpgkey=https://nginx.org/keys/nginx_signing.key
    
    [nginx-mainline]
    name=nginx mainline repo
    baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
    gpgcheck=1
    enabled=0
    gpgkey=https://nginx.org/keys/nginx_signing.key
    EOF
  • 寫入複製 nginx.repo 指令到docker鏡像中

    COPY nginx.repo /etc/yum.repos.d/nginx.repo
  • 使用yum安裝nginx並設置爲開機啓動

    RUN yum makecache && 
        yum install nginx && 
        chkconfig nginx on

安裝 php

centos 默認源中擁有低版本的 php 以及相關包 , 我們需要換一個版本新一些的源 .
本文 remi開源鏡像
  • 安裝 remi 源

    RUN rpm -ivh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm && 
    yum update -y 
  • 使用 yum 安裝php和相關包並設置爲開機啓動

    RUN yum install -y --enablerepo=remi --enablerepo=remi-php72 
        php 
        php-openssl 
        php-curl 
        php-bcmath 
        php-devel 
        php-mbstring 
        php-mcrypt 
        php-mysqlnd 
        php-pdo 
        php-gd 
        php-xml 
        php-opcache 
        php-fpm && 
        chkconfig php-fpm on

清理工作

衆所周知,如果要推送到線上的話鏡像越小越好,docker yum 的運行會生成大量緩存,那麼我們就很有必要做一些清理工作了
RUN yum clean headers && 
    yum clean packages && 
    yum clean metadata && 
    rm -rf /usr/share/man

聲明鏡像運行時入口點

即容器運行時執行的第一個命令,如果不是 init 的話很有可能部分特權命令無法運行,例如 chkconfig
ENTRYPOINT ["/sbin/init"]

合併 dockerfile

dockerfile 中的每個指令都會單獨生成一層鏡像,這樣勢必會增加我們的鏡像體積
通常做法是儘可能把多條指令整理順序合併爲一條,就可以有效減小鏡像體積
FROM centos

# 複製兩個repo
COPY conf/tsinghua-base.repo /etc/yum.repos.d/CentOS-Base.repo
COPY conf/nginx.repo /etc/yum.repos.d/nginx.repo

# 安裝組件和相關包
RUN yum makecache &&      
    yum -y install nginx && 
    chkconfig nginx on && 
    yum install -y epel-release && 
    rpm -ivh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm && 
    yum update -y && 
    yum install -y --enablerepo=remi --enablerepo=remi-php72 
    php 
    php-openssl 
    php-curl 
    php-bcmath 
    php-devel 
    php-mbstring 
    php-mcrypt 
    php-mysqlnd 
    php-pdo 
    php-gd 
    php-xml 
    php-opcache 
    php-fpm && 
    chkconfig php-fpm on && 
    yum clean headers && 
    yum clean packages && 
    yum clean metadata && 
    rm -rf /usr/share/man

# 聲明入口點
ENTRYPOINT ["/sbin/init"]

測試鏡像可用性

  • 構建鏡像

    值得注意的是 nginx 官方 repo 並不是很穩定 , 運行時可能會出錯 , 重試幾次一般都可以成功
    如果是其他類型的錯誤,那麼就要檢查環境以及 dockerfile 有沒有問題
    docker build . -t first-build
  • 帶有特權啓動一個後臺運行的容器,將會返回一個ID

    使用了 --privileged 選項之後,容器會擁有真的 root 權限,否則就只有本地普通用戶權限.容器中執行了某些特殊操作(例如 systemctl)時才需要該選項
    docker run -d --privileged first-build
  • 測試鏡像的運行狀況

    docker exec -it ( docker run 命令返回的ID ) ps aux | grep '[nginx|php]'

    如果返回結果類似這樣,那麼說明我們的操作是正確的

    > docker exec -it cca6 ps aux | grep '[nginx|php]'
    root         1  0.0  0.0  43112  4888 ?        Ss   09:15   0:00 /sbin/init
    root        17  0.0  0.0  39096  6476 ?        Ss   09:15   0:00 /usr/lib/system
    root        29  0.1  0.0  35100  3308 ?        Ss   09:15   0:00 /usr/lib/system
    root       370  0.0  0.1 371588 21424 ?        Ss   09:15   0:00 php-fpm: master
    root       381  0.0  0.0  24264  2784 ?        Ss   09:15   0:00 /usr/lib/system
    dbus       386  0.0  0.0  58000  4164 ?        Ss   09:15   0:00 /usr/bin/dbus-d
    root       418  0.0  0.0  46432   980 ?        Ss   09:15   0:00 nginx: master p
    nginx      421  0.0  0.0  46832  3512 ?        S    09:15   0:00 nginx: worker p
    root       564  0.0  0.0   8096  1820 tty1     Ss+  09:15   0:00 /sbin/agetty --
    apache     822  0.0  0.0 371588 12468 ?        S    09:15   0:00 php-fpm: pool w
    apache     825  0.0  0.0 371588 12468 ?        S    09:15   0:00 php-fpm: pool w
    root      2859  0.0  0.0  51752  3448 pts/0    Rs+  09:21   0:00 ps aux
  • 此時如果使用了端口映射來啓動鏡像,那麼你甚至可以在本地瀏覽器裏看到 nginx 的默認歡迎頁

    docker run -d --privileged -p 8080:80 first-build


推送鏡像到阿里雲容器服務

  • 註冊阿里雲命名空間
進入阿里雲鏡像控制檯,
https://cr.console.aliyun.com/cn-zhangjiakou/instances/repositories      

界面大概長像這樣

  • 使用鏡像加速器

點開左下角的鏡像加速器https://cr.console.aliyun.com/cn-zhangjiakou/instances/mirrors,你會看到你專屬的加速鏈接

找到你的操作系統,逐條執行即可,本文使用 Ubuntu 版本.
可見執行很順利,沒有任何異常

  • 登錄到阿里雲docker倉庫
sudo docker login --username=你的阿里雲用戶名 registry.cn-zhangjiakou.aliyuncs.com
Password: 你的阿里雲密碼
Login Succeeded
  • 建立命名空間

點擊左側的命名空間,點擊創建命名空間,輸入你的命名空間名稱

命名空間可以理解爲鏡像所屬的組織
例如: centos 鏡像的全名是 docker.io/centos,docker.io 就是centos鏡像的命名空間,但是docker.io這個命名空間下卻存在不止centos一種鏡像.

公開和私有是指鏡像是否可以在阿里雲鏡像市場中被大衆查看和是否能夠不需要任何權限拉取

  • 建立倉庫

剛纔我們已經創建好了命名空間,那麼接下來就是創建倉庫了.

倉庫可以理解爲組織創建的軟件包包名
例如: centos 鏡像的全名是 docker.io/centos,centos 就是docker.io的一個倉庫(軟件),同時centos這個軟件可以有很多個版本.

進入 https://cr.console.aliyun.com/cn-zhangjiakou/instances/repositories 倉庫頁面 , 點擊新建倉庫.

命名空間選擇剛纔創建好的,摘要即爲鏡像簡介.

點擊下一步,代碼源選擇本地倉庫

點擊創建鏡像倉庫之後,就會發現頁面上多了一行數據,說明創建成功

鼠標放到那個下載一樣的圖標上,會看到倉庫的專屬地址

  • 修改鏡像名

我們要把我們剛纔構建的一個叫做 first-build 的鏡像推送到阿里雲倉庫中.首先我們使用 docker images | grep first-build 查找到它鏡像ID.接下來我們修改鏡像的名字爲符合docker第三方倉庫的鏡像名格式.

第三方鏡像倉庫鏡像名格式:倉庫地址/組織/鏡像名:鏡像版本號

以阿里云爲例:阿里雲倉庫地址/命名空間/倉庫名:版本 registry.cn-zhangjiakou.aliyuncs.com/leasn-docker/learn-docker:1

然後執行以下命令來修改:

docker tag 3482e8529a90 registry.cn-zhangjiakou.aliyuncs.com/leasn-docker/learn-docker:1

再次使用 docker images | grep first-build 發現已經找不到了,因爲它的名字已經變掉了

  • 推送鏡像
sudo docker push registry.cn-zhangjiakou.aliyuncs.com/leasn-docker/learn-docker


等所有的 Pushing 運行結束之後我們會發現阿里雲倉庫中多了一個版本.

至此,鏡像已經推送成功.我們已經可以基於阿里雲的支持,在全世界範圍內使用我們的鏡像.

對於向開源事業無私奉獻的阿里雲致敬


封裝項目運行鏡像

現在我們就要研究怎麼讓鏡像跑我們自己的項目了
  • 這次就可以基於我們推送阿里雲的鏡像了

    FROM registry.cn-zhangjiakou.aliyuncs.com/leasn-docker/learn-docker:1
  • 複製我們準備好的 nginx.conf 到鏡像裏

    COPY nginx.conf /etc/nginx/conf/nginx.conf

    nginx.conf 全文

    user nginx;
    worker_processes auto;
    pid /run/nginx.pid;
    
    events {
        worker_connections 1024;
    }
    
    http {
        server {
            listen       80;
            server_name  127.0.0.1;
            root         /var/www/html;
            index        index.php;
    
            location ~ \.php($|/) {
                fastcgi_pass    127.0.0.1:9000;
                fastcgi_index   index.php;
                fastcgi_split_path_info ^(.+\.php)(.*)$;
                fastcgi_param   PATH_INFO $fastcgi_path_info;
                fastcgi_param   SCRIPT_FILENAME   $document_root$fastcgi_script_name;
                include         fastcgi_params;
            }
        }
    }
  • 複製工程源碼到鏡像裏

    在當前目錄建立我們的工程,並且假裝我們的工程只有一個文件,它位於./proj

    複製我們的工程到鏡像裏併爲運行目錄加權

    COPY proj /var/www/html
    RUN chmod -R 755 /var/www/html/

    Dockerfile 全文

    FROM registry.cn-zhangjiakou.aliyuncs.com/leasn-docker/learn-docker:1
    COPY nginx.conf /etc/nginx/nginx.conf
    
    COPY proj /var/www/html
    RUN chmod -R 755 /var/www/html/

    構建鏡像並使用端口映射運行我們的容器

    docker build .
    docker run --privileged -d -p 8080:80 773ed8872493

    如果不出意外,我們已經可以在本地的 127.0.0.1:8080 中看到 phpinfo() 了

    既然phpinfo已經看到了,那麼如何讓整個工程跑起來我就不贅述了.

值得一提的是,推送新版本到

使用 docker-compose 編排鏡像

Compose 是一個用於定義和運行多容器Docker應用程序的工具。使用Compose,您可以使用YAML文件來配置應用程序的服務。然後,使用單個命令,您可以從配置中創建並啓動所有服務

該應用使用 sudo apt install docker-compose 安裝

  • 調整目錄結構

    在我們現在工作目錄外面再加一層目錄,大致是: 工作目錄 > docker-learn (以前的工作目錄) && docker-compose.yaml

    目錄樹形結構:

  • 編輯 docker-compose.yaml
docker-compose 包含多個指令,並採用yaml語言編寫.可以理解爲把我們在命令行運行的 run 命令參數寫到了文件裏,經過統一的工具協調啓動.
主要指令: 
version 版本信息,不知道爲什麼必須是 3
version: 3
services 需要編排的服務列表,本次我們主要編寫一個叫做 docker-learn 的服務
services: 
  • docker-compose.yaml 全文

    version: '3'
    services:
        # 服務名
        docker-learn:
            # 該服務是否以特權啓動 , 即 --privileged
            privileged: true
            # 構建
            build:
                # 構建上下文 即: docker build ./docker-learn
                context: ./docker-learn 
            # 端口映射,即 -p 80:80
            ports:
                - 80:80
            # 對外暴露的端口 ,相當於Dockerfile 的 EXPOSE 指令 
            # EXPOSE指令只是聲明瞭容器應該打開的端口,但是並沒有實際上將它打開!
            # 該選項在 docker run -it -P(大寫) 時會真的起作用
            expose:
                - 80
            # 目錄映射 , 相當於 docker run -v 
            # volumes:
            #    - ./logs/php-fpm:/var/log/php-fpm
            #     - ./logs/nginx:/var/log/nginx
  • 使用docker-compose 啓動鏡像

    關閉其他運行中的容器,以免與我們即將運行的容器衝突

       docker ps | awk '{print $1}' | grep -v CON | xargs docker kill

    啓動鏡像

    單獨 up 不使用服務名會運行 services 中定義的所有容器.
    如果services中有多個服務,那麼可以使用 up 服務名來單獨 up 一個服務容器
    up 默認會使用 build:context 中的 Dockerfile 文件編譯好的鏡像進行容器啓動,--build 是強制再次使用 Dockerfile 進行重新編譯鏡像再啓動 . 但是 --build 仍然會使用已經存在的鏡像層的緩存
    --force-recreate 重新編譯時不使用鏡像層緩存 , 完全重新編譯

    如果出現 bind: address already in use 類似的提示 , 就換一個 ports 裏的綁定端口重試

    docker-compose up [docker-learn] [--build] [--force-recreate]

    我們發現現在訪問 127.0.0.1:8080 仍然可以看到 phpinfo

接入 jenkins 進行持續集成

更新中

接入 kubernetes

更新中

大功告成

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