2019 iT 邦幫忙鐵人賽

DAY 29
Cloud Native

從零開始建立自動化發佈的流水線系列 第 29

29. Docker 與 CI/CD (上)

筆者語: 依舊來不及在 12 點前完稿,先發半成稿,早上先補完。

Eric: docker 與 docker compose 的方式,剛剛我們都己經有嘗試過了。接著,我們將剛剛的動作轉移到 CI Server 上吧。

吉米: 來吧。

1. Travis CI

在 Travis CI 上,說明了 5 種 docker 的建置方式,但筆者只針對 dockerfiledocker-compose 的部份介紹。若對其他方式有興趣,可以直接上 Travis CI 官網觀看。

不管是那邊方式,都必須先設定啟用 docker 的服務。所以增加以下的片段到 .travis.yml

# .travis.yml

  - docker

1.1 dockerfile

# .travis.yml

sudo: required

language: ruby

  - docker

  - docker build -t carlad/sinatra .
  - docker run -d -p carlad/sinatra /bin/sh -c "cd /root/sinatra; bundle exec foreman start;"
  - docker ps -a
  - docker run carlad/sinatra /bin/sh -c "cd /root/sinatra; bundle exec rake test"

  - bundle exec rake test

1.2 docker-compose

# .trvis.yml


  - sudo rm /usr/local/bin/docker-compose
  - curl -L${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
  - chmod +x docker-compose
  - sudo mv docker-compose /usr/local/bin

2. Azure DevOps

若希望 Azure Pipelines 可以程式建置為 docker 可使用的物式件,需對 azure-pipelines.yml 進行對應的變動。

2.1 使用 dockerfile

You can build a Docker image by running the docker build command in a script or by using the Docker task.

- script: docker build -t $(dockerId)/$(imageName) .  # add options to this command to meet your needs

Often you'll want to build and test your app before creating the Docker image. You can orchestrate this process either in your build pipeline or in your Dockerfile.

Build and test in your build pipeline

In this approach, you use the build pipeline to orchestrate building your code, running your tests, and creating an image. This approach is useful if you want to:

  • Leverage tasks (either built-in tasks or those you get from the Marketplace) to define the pipeline used to build and test your app.
  • Run tasks that require authentication via service connections (for example: authenticated NuGet or npm feeds).
  • Publish test results.

To create an image, you run a docker build command at the end of your build pipeline. Your Dockerfile contains the instructions to copy the results of your build into the container.

The instructions in the above example demonstrate this approach. The test results published in the example, can be viewed under Tests Tab in build.

Build and test in your Dockerfile

In this approach, you use your Dockerfile to build your code and run tests. The build pipeline has a single step to run docker build. The rest of the steps are orchestrated by the Docker build process. It's common to use a multi-stage Docker build in this approach. The advantage of this approach is that your build process is entirely configured in your Dockerfile. This means your build process is portable from the development machine to any build system. One disadvantage is that you can't leverage Azure Pipelines and TFS features such as tasks, jobs, or test reporting.

For an example on using this approach, follow these steps:

  1. The sample repos that you used in the example above also include a Dockerfile.multistage for this approach:

    • Dockerfile.multistage in .NET Core sample

      # First stage of multi-stage build
      FROM microsoft/aspnetcore-build:2.0 AS build-env
      WORKDIR /app
      # copy the contents of agent working directory on host to workdir in container
      COPY . ./
      # dotnet commands to build, test, and publish
      RUN dotnet restore
      RUN dotnet build -c Release
      RUN dotnet test dotnetcore-tests/dotnetcore-tests.csproj -c Release --logger "trx;LogFileName=testresults.trx"
      RUN dotnet publish -c Release -o out
      # Second stage - Build runtime image
      FROM microsoft/aspnetcore:2.0
      WORKDIR /app
      COPY --from=build-env /app/dotnetcore-sample/out .
      ENTRYPOINT ["dotnet", "dotnetcore-sample.dll"]

    Replace the content in the Dockerfile at the root of your repository with the content from Dockerfile.multistage.

  2. Then, define your build pipeline:

  vmImage: 'ubuntu-16.04'

  - script: docker build -t $(dockerId)/$(dockerImage) . # include other options to meet your needs

2.2 使用 docker-compose

Docker Compose enables you to bring up multiple containers and run tests. For example, you can use a docker-compose.yml file to define two containers that need to work together to test your application: a web service that contains your application and a test driver. You can build new container images every time you push a change to your code. You can wait for the test driver to finish running tests before bringing down the two containers.

If you use Microsoft-hosted agents, you don't have to run any additional steps to install and use docker-compose.

To extend the above example to use docker-compose:

  1. Your sample repo already includes a docker-compose.yml file in the docs folder.
  2. Add a Bash step to your build pipeline:
- script: |
    docker-compose -f docs/docker-compose.yml --project-directory . -p docs up -d
    docker wait docs_sut_1
    docker-compose -f docs/docker-compose.yml --project-directory . down

If you can't upgrade, another way to solve this problem is to explicitly create another test driver as a container within the composition, as we did in the example above. Another solution is to use docker-compose exec and target a specific container in the composition from your script.

Eric: 休息一下,等等再來試著整合 Docker 與 Jenkins 。

吉米: 嗯嗯,我先理清剛剛說的內容。

<< 待續 >>


  1. Travis CI Document, Using Docker in Builds
  2. Microsoft document, Build Docker apps with Azure Pipelines or Team Foundation Server
  3. Micorsoft Document, Docker task
  4. Microsoft Document, Docker 應用程式的外部迴圈 DevOps 工作流程中的步驟

28. Docker - Docker Compose
30. Docker 與 CI/CD (下)