docker + makefile =CI Pipeline

简介: docker + makefile =CI Pipeline

docker + makefile =CI Pipeline

文章目录

docker + makefile =CI Pipeline

1. 简单的docker&makefile

1.1 编辑 dockerfile

1.2 编辑 Makefile

1.3 执行 make

2. docker & Makefile 实战

2.1 编写 Makefile

2.2 处理 UID

2.3 执行 make

2.4 开发小技巧

1. 简单的docker&makefile

1.1 编辑 dockerfile

$ cat Dockerfile
FROM busybox
CMD ["date"]

1.2 编辑 Makefile

build:
    docker build -t benhall/docker-make-example .
run:
    docker run benhall/docker-make-example
default: build test

1.3 执行 make

#通过dockerfile构建容器
$ make
docker build -t benhall/docker-make-example .
Sending build context to Docker daemon  116.7kB
Step 1/2 : FROM busybox
latest: Pulling from library/busybox
24fb2886d6f6: Pull complete 
Digest: sha256:f7ca5a32c10d51aeda3b4d01c61c6061f497893d7f6628b92f822f7117182a57
Status: Downloaded newer image for busybox:latest
 ---> 16ea53ea7c65
Step 2/2 : CMD ["date"]
 ---> Running in 26d6f36ad3b4
Removing intermediate container 26d6f36ad3b4
 ---> 339b5a708dce
Successfully built 339b5a708dce
Successfully tagged benhall/docker-make-example:latest
#查看构建效果
$ docker images |grep benha
benhall/docker-make-example   latest      339b5a708dce   2 minutes ago    1.24MB
#运行容器
$ make run
docker run benhall/docker-make-example
Mon Sep 27 08:36:15 UTC 2021
$ docker ps |grep ben
$ docker ps -a |grep ben
c8cf9f9b7090   benhall/docker-make-example   "date"                   14 seconds ago   Exited (0) 13 seconds ago             amazing_buck
#一次性构建部署
$ make build run
docker build -t benhall/docker-make-example .
Sending build context to Docker daemon  116.7kB
Step 1/2 : FROM busybox
 ---> 16ea53ea7c65
Step 2/2 : CMD ["date"]
 ---> Using cache
 ---> 339b5a708dce
Successfully built 339b5a708dce
Successfully tagged benhall/docker-make-example:latest
docker run benhall/docker-make-example
Mon Sep 27 08:38:11 UTC 2021

我希望我所有的项目都能像这样工作:

git pull && make test && make build && make deploy

2. docker & Makefile 实战

项目:https://github.com/Ghostwritten/dockerbuild

2.1 编写 Makefile

版权作者说明
# --------------------------------------------------------------------
# Copyright (c) 2019 LINKIT, The Netherlands. All Rights Reserved.
# Author(s): Anthony Potappel
# 
# This software may be modified and distributed under the terms of the
# MIT license. See the LICENSE file for details.
# --------------------------------------------------------------------
# If you see pwd_unknown showing up, this is why. Re-calibrate your system.
#条件赋值 ( ?= ) 如果变量未定义,则使用符号中的值定义变量。如果该变量已经赋值,则该赋值语句无效。
PWD ?= pwd_unknown
# PROJECT_NAME defaults to name of the current directory.
# should not to be changed if you follow GitOps operating procedures.
PROJECT_NAME = $(notdir $(PWD))
# Note. If you change this, you also need to update docker-compose.yml.
# only useful in a setting with multiple services/ makefiles.
#简单赋值 ( := ) 编程语言中常规理解的赋值方式,只对当前语句的变量有效。
SERVICE_TARGET := main
# if vars not set specifially: try default to environment, else fixed value.
# strip to ensure spaces are removed in future editorial mistakes.
# tested to work consistently on popular Linux flavors and Mac.
ifeq ($(user),)
# USER retrieved from env, UID from shell.
HOST_USER ?= $(strip $(if $(USER),$(USER),nodummy))
HOST_UID ?= $(strip $(if $(shell id -u),$(shell id -u),4000))
else
# allow override by adding user= and/ or uid=  (lowercase!).
# uid= defaults to 0 if user= set (i.e. root).
HOST_USER = $(user)
HOST_UID = $(strip $(if $(uid),$(uid),0))
endif
THIS_FILE := $(lastword $(MAKEFILE_LIST))
CMD_ARGUMENTS ?= $(cmd)
# export such that its passed to shell functions for Docker to pick up.
export PROJECT_NAME
export HOST_USER
export HOST_UID
# all our targets are phony (no files to check).
.PHONY: shell help build rebuild service login test clean prune
# suppress makes own output
#.SILENT:
# shell is the first target. So instead of: make shell cmd="whoami", we can type: make cmd="whoami".
# more examples: make shell cmd="whoami && env", make shell cmd="echo hello container space".
# leave the double quotes to prevent commands overflowing in makefile (things like && would break)
# special chars: '',"",|,&&,||,*,^,[], should all work. Except "$" and "`", if someone knows how, please let me know!).
# escaping (\) does work on most chars, except double quotes (if someone knows how, please let me know)
# i.e. works on most cases. For everything else perhaps more useful to upload a script and execute that.
shell:
ifeq ($(CMD_ARGUMENTS),)
  # no command is given, default to shell
  docker-compose -p $(PROJECT_NAME)_$(HOST_UID) run --rm $(SERVICE_TARGET) sh
else
  # run the command
  docker-compose -p $(PROJECT_NAME)_$(HOST_UID) run --rm $(SERVICE_TARGET) sh -c "$(CMD_ARGUMENTS)"
endif
# Regular Makefile part for buildpypi itself
help:
  @echo ''
  @echo 'Usage: make [TARGET] [EXTRA_ARGUMENTS]'
  @echo 'Targets:'
  @echo '  build      build docker --image-- for current user: $(HOST_USER)(uid=$(HOST_UID))'
  @echo '  rebuild    rebuild docker --image-- for current user: $(HOST_USER)(uid=$(HOST_UID))'
  @echo '  test       test docker --container-- for current user: $(HOST_USER)(uid=$(HOST_UID))'
  @echo '  service    run as service --container-- for current user: $(HOST_USER)(uid=$(HOST_UID))'
  @echo '  login    run as service and login --container-- for current user: $(HOST_USER)(uid=$(HOST_UID))'
  @echo '  clean      remove docker --image-- for current user: $(HOST_USER)(uid=$(HOST_UID))'
  @echo '  prune      shortcut for docker system prune -af. Cleanup inactive containers and cache.'
  @echo '  shell      run docker --container-- for current user: $(HOST_USER)(uid=$(HOST_UID))'
  @echo ''
  @echo 'Extra arguments:'
  @echo 'cmd=:  make cmd="whoami"'
  @echo '# user= and uid= allows to override current user. Might require additional privileges.'
  @echo 'user=: make shell user=root (no need to set uid=0)'
  @echo 'uid=:  make shell user=dummy uid=4000 (defaults to 0 if user= set)'
rebuild:
  # force a rebuild by passing --no-cache
  docker-compose build --no-cache $(SERVICE_TARGET)
service:
  # run as a (background) service
  docker-compose -p $(PROJECT_NAME)_$(HOST_UID) up -d $(SERVICE_TARGET)
login: service
  # run as a service and attach to it
  docker exec -it $(PROJECT_NAME)_$(HOST_UID) sh
build:
  # only build the container. Note, docker does this also if you apply other targets.
  docker-compose build $(SERVICE_TARGET)
clean:
  # remove created images
  @docker-compose -p $(PROJECT_NAME)_$(HOST_UID) down --remove-orphans --rmi all 2>/dev/null \
  && echo 'Image(s) for "$(PROJECT_NAME):$(HOST_USER)" removed.' \
  || echo 'Image(s) for "$(PROJECT_NAME):$(HOST_USER)" already removed.'
prune:
  # clean all that is not actively used
  docker system prune -af
test:
  # here it is useful to add your own customised tests
  docker-compose -p $(PROJECT_NAME)_$(HOST_UID) run --rm $(SERVICE_TARGET) sh -c '\
    echo "I am `whoami`. My uid is `id -u`." && echo "Docker runs!"' \
  && echo success

2.2 处理 UID

未配置 UserID (UID) 时,Docker 会将容器默认为用户 root。当您开始处理生产系统时,需要练习正确配置用户。你可以在Dockers 的最佳实践列表上阅读它,来自 K8s 的这篇文章也很好地涵盖了它。


当您在 Mac 上本地运行测试时,root 会映射到您自己的用户,因此一切正常。生产平台——应该——被配置为用户隔离,但这并不总是默认的。例如,如果您在 Linux 系统上运行测试(没有重新映射),您可能会偶然发现 Docker 生成的文件归 root 所有的问题。


当您在一个系统上有多个用户时,您也会遇到问题。即使您不共享一个系统,运行并行测试也同样需要分离。而且,如果没有正确的 UID 设置,您甚至如何传递凭据(例如,通过将卷链接为 ~/.ssh 和 ~/.aws)?后者是处理基础设施部署时的常见模式。

如果你开始成为一个更密集的 docker-consumer,你的团队会成长并且事情会变得复杂,最终你会想要或需要在你的所有项目中嵌入 UID 分离。


幸运的是,尽早配置 UID 是(相对)容易的。虽然我花了一些练习才能获得良好的设置,但我现在有一个模板(假设使用 Makefile)自动完成所有操作,成本几乎为零。

以下是要使用的docker-compose文件的副本:

version: '3.4'
services:
  main:
    # Makefile fills PROJECT_NAME to current directory name.
    # add UID to allow multiple users run this in parallel
    container_name: ${PROJECT_NAME}_${HOST_UID:-4000}
    hostname: ${PROJECT_NAME}
    # These variables are passed into the container.
    environment:
      - UID=${HOST_UID:-4000}
    # Run with user priviliges by default.
    user: ${HOST_USER:-nodummy}
    image: ${PROJECT_NAME}:${HOST_USER:-nodummy}
    build:
      context: .
      # Build for current user.
      target: user
      dockerfile: Dockerfile
      # These variables are passed to Dockerfile.
      args:
        - HOST_UID=${HOST_UID:-4000}
        - HOST_USER=${HOST_USER:-nodummy}
    # Run container as a service. Replace with something useful.
    command: ["tail", "-f", "/dev/null"]
    # Copy current (git-) project into container.
    volumes:
      - ${PWD:-.}:/home/${HOST_USER}/${PROJECT_NAME}

默认变量的一种写法

${HOST_USER:-nodummy} 
${HOST_UID:-4000}

这会从您的运行时复制变量,如果不存在,则分别默认为“nodummy”和“4000”。如果您不喜欢默认值,请执行以下操作:

${HOST_USER:?You forgot to set HOST_USER in .env!}
${HOST_UID:?You forgot to set HOST_UID in .env!}

注意“HOST_”前缀。我避免直接使用 USER 和 UID。不保证这些变量在运行时可用。USER 通常在 shell 中可用,但 UID 主要是 Docker 不会获取的环境变量。拥有单独的命名方案可以防止意外,并允许灵活配置自动化管道。

Dockerfile内容如下:

FROM alpine as base
RUN apk update \
    && apk add --no-cache \
        bash
FROM scratch as user
COPY --from=base . .
ARG HOST_UID=${HOST_UID:-4000}
ARG HOST_USER=${HOST_USER:-nodummy}
RUN [ "${HOST_USER}" == "root" ] || \
    (adduser -h /home/${HOST_USER} -D -u ${HOST_UID} ${HOST_USER} \
    && chown -R "${HOST_UID}:${HOST_UID}" /home/${HOST_USER})
USER ${HOST_USER}
WORKDIR /home/${HOST_USER}

在这里,我们构建了一个小型(只有 10MB,微服务 FTW!)Alpine 容器,添加了 bash 以供娱乐和练习。我们应用所谓的分阶段构建的概念来保持基础镜像(可重用构建组件)与用户镜像(为特定运行准备的镜像)分离。


使用 Makefile 时,所有变量都会自动设置。这个 Dockerfile 在没有 Makefile 的情况下也能正常工作,但用户仍然可以在自己的运行时或单独的env-file 中配置变量.

如果您处于开发模式,您可能会遇到某些障碍,需要您以 root 用户身份进行故障排除。

make shell user=root

2.3 执行 make

# download our files
git clone https://github.com/LINKIT-Group/dockerbuild
# enter directory
cd dockerbuild
# build, test and run a command
make build test shell cmd="whoami"
# my favorite for container exploration
make shell
# shell-target is the default (first item), so this also works: 
make cmd="whoami"
make cmd="ls /"
# force a rebuild, test and cleanup
make rebuild test clean

2.4 开发小技巧

  • 运行容器最好加上–rm
  • 我们还可以加其他目标任务,比如将镜像推送到仓库。

参考:

相关文章
|
28天前
|
jenkins Shell 持续交付
自动化部署:使用Jenkins和Docker实现CI/CD
【8月更文挑战第31天】 本文旨在引导读者了解如何通过Jenkins和Docker来实现持续集成和持续部署(CI/CD),从而优化开发流程,提升工作效率。文章将详细介绍配置Jenkins服务器、创建Docker镜像以及设置自动化构建和部署的步骤。通过实际操作案例,我们将展示如何将代码变更快速部署到测试或生产环境,确保软件质量与发布速度的双重保障。
|
30天前
|
前端开发 jenkins 持续交付
jenkins学习笔记之二十:docker in docker运行pipeline
jenkins学习笔记之二十:docker in docker运行pipeline
|
1月前
|
测试技术 持续交付 开发者
使用Docker构建CI/CD流程:从理论到实践
【8月更文挑战第2天】使用Docker构建CI/CD流程,可以显著提高软件开发的效率和质量。通过容器化技术,开发者可以确保环境的一致性,快速部署和测试应用,并减少人为错误。结合合适的CI/CD工具和最佳实践,可以进一步加速软件交付过程,提高用户满意度。希望本文能为开发者在构建基于Docker的CI/CD流程时提供有价值的参考。
|
2月前
|
Kubernetes Cloud Native 持续交付
云原生架构的核心组成部分通常包括容器化(如Docker)、容器编排(如Kubernetes)、微服务架构、服务网格、持续集成/持续部署(CI/CD)、自动化运维(如Prometheus监控和Grafana可视化)等。
云原生架构的核心组成部分通常包括容器化(如Docker)、容器编排(如Kubernetes)、微服务架构、服务网格、持续集成/持续部署(CI/CD)、自动化运维(如Prometheus监控和Grafana可视化)等。
|
4月前
|
存储 测试技术 持续交付
【Docker 专栏】Docker 与 CI/CD 的集成策略
【5月更文挑战第8天】本文探讨了Docker在CI/CD流程中的作用,强调了环境一致性、快速部署和资源隔离等优势。通过在构建、测试和部署阶段集成Docker,可以提升软件开发效率和质量。具体集成策略包括使用Dockerfile构建镜像、整合CI/CD工具如Jenkins和GitLab。集成带来的好处包括提高效率、增强可靠性、加速交付和简化管理。然而,也需应对镜像管理、网络配置和安全等问题。通过案例分析,证明了Docker与CI/CD集成的有效性和必要性。
100 2
【Docker 专栏】Docker 与 CI/CD 的集成策略
|
4月前
|
jenkins Java 持续交付
Jenkins与Docker的自动化CI/CD实战
Jenkins与Docker的自动化CI/CD实战
|
4月前
|
Devops 开发工具 数据安全/隐私保护
Docker Swarm总结+CI/CD Devops、gitlab、sonarqube以及harbor的安装集成配置(3/5)
Docker Swarm总结+CI/CD Devops、gitlab、sonarqube以及harbor的安装集成配置(3/5)
224 0
|
4月前
|
存储 jenkins 持续交付
百度搜索:蓝易云【Docker+Rancher+Harbor+GitLab+Jenkins搭建CI/CD环境】
请注意,上述步骤仅为一个示例,实际搭建过程可能因环境和需求的不同而有所变化。因此,在实际操作中,请参考相应工具的官方文档和指南,以确保正确地配置和集成这些工具。
98 3
|
4月前
|
jenkins 测试技术 持续交付
深入理解CI/CD与Docker集成:自动化构建和部署的完整指南
在当今软件开发的快节奏环境中,自动化构建和部署是实现敏捷开发和DevOps实践的关键。Docker容器技术为这一过程引入了更高的灵活性和一致性。本文将深入研究如何将持续集成/持续部署(CI/CD)与Docker集成,提供更详细、实用的示例代码,以帮助大家全面了解并成功应用这一重要的DevOps实践。
|
Kubernetes 持续交付 开发者
使用 Docker 和 Kubernetes 实现持续集成和持续部署(CI/CD)
使用 Docker 和 Kubernetes 实现持续集成和持续部署,可以为开发团队带来更高效、稳定的交付流程。这种自动化的部署方式能够显著提高交付速度、降低发布风险,并为应用的扩展和管理提供了强大的工具。然而,构建一个完善的 CI/CD 环境需要根据团队的需求和实际情况进行调整和优化。
1165 1
使用 Docker 和 Kubernetes 实现持续集成和持续部署(CI/CD)