Docker

近期使用Docker打包镜像遇到的问题总结

背景 #

github.com/yeqown/goreportcard 项目中我改造了 goreportcard。 后续为了方便部署,我准备将其打包成为docker镜像并上传到 DockerHub。期间遇到了下面的问题,并一一解决,这里做一个记录帮助以后遇到类似的问题可以快速解决。

初期的目标是:将goreportcardgolangci-lint编译好,尽可能较小镜像的体积。因此第一次尝试,我使用了分阶段编译,用golang:1.14.1编译,alpine来发布。

基本 Dockerfile 如下:

# building stage
FROM golang:1.14-alpine3.11 as build
WORKDIR /tmp/build

COPY . .
RUN export GOPROXY="https://goproxy.cn,direct" \
    && go mod download \
    && go build -o app ./cmd/goreportcard-cli/ \
    && go get github.com/golangci/golangci-lint && go install github.com/golangci/golangci-lint/cmd/golangci-lint

# release stage
FROM golang:1.14-alpine3.11 as release
WORKDIR /app/goreportcard

COPY --from=build /tmp/build/app .
COPY --from=build /tmp/build/tpl ./tpl
COPY --from=build /tmp/build/assets ./assets

# FIXED: 不能使用golangci-lint, `File not found` 错误
COPY --from=build /go/bin/golangci-lint /usr/local/bin

EXPOSE 8000

ENTRYPOINT ["./app", "start-web", "&"]

问题清单和解决方案 #

由于并不是所有的问题都和Docker有关,因此我会使用 [分类] 在标题上注明。

...

docker+jenkins+golang持续集成实践


起因 #

因为生产需要最近又重新折腾了一下Jenkins和docker。主要目的是想自动编译,打包,部署一些Golang的HttpServer。于是决定使用Jenkins来做这个持续集成的载体,选择Jenkins出于两点原因:

1. 以前就使用过,上手会更快 2. 社区比较成熟,插件和文档丰富


安装Docker和Pull Jenkins镜像 #

这一步,作为前置条件且不是本文主要要描述的步骤,因此略去。网上也有很多参考资料~


Jenkins & docker-compose配置 #

为了方便我才用了docker-compose这个工具,docker-compose 基础可以参见我的docker-compose上手。这里直接上配置:

version: '2'

services:
  jenkins:
    container_name: jenkins-lts
    ports:
      - 9001:8080
      - 50000:50000
    image: jenkins/jenkins:lts
    volumes:
      - /home/worker/jenkins/jenkins_home:/var/jenkins_home

配置也是官方的示例配置。

Note: 将宿主机的/home/worker/jenkins/jenkins_home挂载为容器的/var/jenkins_home目录。这样做的目的是,如果容器被不小心删除也不至于Jenkins的数据丢失。

到这里,我们只需要执行docker-compose up -d便可以将Jenkins容器跑起来了,再配置一下Nginx,便可以直接访问到Jenkins页面了,并进行初始化。

我的目录结构如下:

➜  jenkins ll
total 8.0K
-rw-rw-r--  1 worker worker  220 May  2 17:19 docker-compose.yml
drwxrwxr-x 19 worker worker 4.0K May  3 15:53 jenkins_home
➜  jenkins pwd
/home/worker/jenkins
➜  jenkins docker-compose up -d # 运行

Publish Over SSH配置 #

Publish Over SSH配置,由于我们是通过docker运行的Jenkins,因此要特别配置一下SSH,方便Jenkins部署项目。这里先列出步骤:

...

Drone体验

相较于Jenkins,Gitlab-CI…等,尝试Drone的首要原因是,天生的docker支持。不用去操心部署CI或者CD的环境配置等等烦心事。只需要上手,如何配置这个CD工具,让我使用更加畅快和顺手。

安装部署 #

前提:已经安装了docker,docker-compose,并基本掌握docker用法,基本熟悉docker-compose配置文件

pull镜像 #

docker pull drone/drone:0.8  # droner-server 镜像
docker pull dorner/agent:0.8 # drone-agent 镜像

也可以跳过这一步,docker运行的时候,如果匹配不到本地镜像,会自动拉取。

docker-compose.yml配置文件 #

为了方便,新建一个Drone文件夹,目录结构如下:

--Drone                  # 文件夹
  |---docker-compose.yml # docker-compose 配置文件
  |---data               # 用于挂载的数据文件
  |---drone.domain.com   # nginx sever 配置文件
  `---other.file         # 其他文件

已知文件结构后,编写的docker-compose.yml文件如下:

version: '2'

services:
  drone-server:
    image: drone/drone:0.8
    container_name: drone-server
    ports:
      - 8000:8000
      - 9000:9000
    volumes:
      - ./data:/var/lib/drone/ # 在没有跟数据库绑定的情况下,默认使用sqlite数据库
    restart: always
    environment:
      - DRONE_OPEN=false
      - DRONE_HOST=http://127.0.0.1:8000 # 最好是在服务器上,localhost无法收到webhook的通知
      - DRONE_ADMIN=yourname

      - DRONE_GITHUB=true
      - DRONE_GITHUB_CLIENT=7bc7971bxxxxx # 需要预先注册一个github oauth应用
      - DRONE_GITHUB_SECRET=9456c630xxxxxxxxxxxxxx

      - DRONE_SECRET=secret
      - DRONE_DEBUG=false

  drone-agent:
    image: drone/agent:0.8
    container_name: drone-agent
    command: agent
    restart: always
    depends_on:
      - drone-server
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - DRONE_SERVER=drone-server:9000
      - DRONE_SECRET=secret
      - DRONE_DEBUG=true

启动Drone #

启动就很简单了,Drone目录下执行:docker-compose up -d,启动结果截图如下: Drone-starting.png 如果是首次打开,会先去github请求授权,然后回调schema://drone.your_domain.com/authorize,如截图: Drone-running-web.png

...

docker-compose上手

docker compose 用于快速在集群中部署分布式应用。按我的理解也可以用于简化部署单个应用。譬如我要使用dock er启动一个nginx服务,需要做端口映射,挂载数据文件,指定镜像…等等,这种情况下,可以将启动容器的命令整合到docker-compose.yml文件中,可以在多个服务器上运行,瞬间就完成了nginx的安装及配置,再也不用去编译,解决环境依赖了,这种感觉实在是太爽了!!!

安装 #

  1. 使用pip pip install docker-compose
  2. 从官方Github Release下载二进制包文件
  3. 其他方法略去

使用场景 #

在日常工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。

实战场景 #

需要部署的项目,只有两个docker容器,一个server,一个db。一般的部署方式是,分别启动两个容器,容器间通过互联的方式通信:

sudo docker run --rm -p 5433:5432 --name postgres -e POSTGRES_PASSWORD=minepwd -e POSTGRES_USER=mineusr -d postgres

sudo docker run --rm -p 9091:9091 --link postgres:postgres --name mineserver -d me/mineserver

这两条命令还是有挺麻烦的,如果记不住,当然可以用shell脚本来运行,可以如果其中某一个服务无法如期运行。。。就很监介了。这时候就可以引入docker-compose了。

编写docker-compose.yml来部署项目 #

version: "2" # 指定docker-compose版本
services:    # 项目依赖的服务
  postgres:  # 服务名字
    image: postgres # 服务需要的docker镜像与docker run命令中的镜像指定方式一致
    volumes:        # 挂载卷,这里的主要目的是,方便同步数据库和数据脚本
      - ./postgres:/var/lib/postgresql/data
      - ./sh:/usr/src/sh
    ports:          # 端口绑定
      - 5433:5432
    container_name: postgres
    environment:    # 设置环境变量
      POSTGRES_PASSWORD: "minepwd"
      POSTGRES_USER: "mineusr"
      POSTGRES_DB: "minedb"
  mineserver:
    image: me/mineserver
    volumes:        # 挂载卷,方便查看输出日志
      - ./logs:/usr/src/mineserver/logs
    ports:
      - 9091:9091
    container_name: mineserver
    links:          # 容器互联
      - postgres:postgres

在编写docker-compose.yml的时候,需要注意的是各个选项的数据类型,不过docker-compose会有提示,也很方便

...

docker+selenium+python构建前端自动化分布式测试环境

docker + selenium + python 构建前端自动化分布式测试环境。利用seleninum-grid分布式框架,python编写测试代码,docker部署来进行前端自动化测试

2018-2-1 更新 使用docker-compose编排

分布式部署的优点 #

自动化的优缺点就不再重复了,主要分析下docke部署和分布式的优势

  • 提高自动化的测试效率(分布式)
  • 方便打包和持续集成(docker)
  • 解决多人coding,却因为路径不一致导致无法运行的问题(当然也可以通过其他方式来解决~)

这里还有一个问题就是:使用docker部署方式运行测试代码,是看不见本地浏览器启动的,因此在调试测试代码的时候,需要一定的工具来协助,譬如VNC viewer

开篇-selenium #

大家都知道 Selenium 是支持多种浏览器多个编程语言的一个自动化测试工具。而 Selenium Grid 是一种可以让用户在不同的环境和不同的浏览器上并行运行 web 测试用例的框架。换而言之,使用 Selenium Grid 可以让我们在分布式测试环境下执行测试,例如 Windows,Linux,Mac OS,Andoid/iOS 等等,这样可以大大减少重复的工作量,提高我们的工作效率。

selenium分布式结构如图: selunium-grid

搭建分布式环境 #

在Dockerhub已经具有了相应的selenium的镜像,我们直接使用就行了

拉取镜像 #

docker pull selenium/hub
docker pull selenium/node-chorme-debug

关于node-chrome-debugnode-chrome的区别: 暂未研究

运行容器 #

docker run -d -p 4444:4444 --name sel-hub selunium/hub # 运行hub服务
docker run -d -p 5900:5900 --link sel-hub:hub selunium/node-chrome-debug # 运行slenium chrome 节点
# more node could append like node-chrome-debug

查看节点信息 #

在浏览器中打开http://127.0.0.1:4444/grid/console 这里需要注意的是,如果是在本地运行的容器,并映射4444端口,因此得到127.0.0.1:4444,如果是在虚拟机中运行,ip和端口应该根据网络来获取相应的IP和PORT

...

docker探索

docker 学习实战笔记。关于docker的详细信息参见官方文档

实战环境配置:

系统 Docker
MacOS 17.12.0-ce

实战一 简单部署可执行文件 #

本次实战是部署一个golang的web服务, 需要mongo, redis支持

  1. 省略代码,打包过程(Mac用户别忘了打包GOOS=linux,0·0)

  2. 编写Dockerfile

FROM alpine # 简版linux

RUN mkdir /app # 在镜像中创建一个文件夹

COPY ./webapp /app 
COPY ./config /app/config
COPY ./logs /app/logs

EXPOSE 35764 # 暴露35764端口,也就是为了从外部可以访问到容器类的服务

WORKDIR /app # 切换到应用文件夹(在镜像执行的时候,会自动切换)
  1. 构建镜像 执行命令 docker build -t tp-api:v1 .

执行结果如下:

Sending build context to Docker daemon   55.5MB
Step 1/7 : FROM alpine
 ---> 3fd9065eaf02
Step 2/7 : RUN mkdir /app
 ---> Using cache
 ---> 6948fdc89bbd
Step 3/7 : COPY ./webapp /app
 ---> Using cache
 ---> 555307961735
Step 4/7 : COPY ./config /app/config
 ---> ab15feb5a3ab
Step 5/7 : COPY ./logs /app/logs
 ---> 0055512da60b
Step 6/7 : EXPOSE 35764
 ---> Running in db0503538961
Removing intermediate container db0503538961
 ---> 1d214b7aff6d
Step 7/7 : WORKDIR /app
Removing intermediate container 42889dd384a7
 ---> f0b05bcb428d
Successfully built f0b05bcb428d
Successfully tagged tp-api:v2
  1. 调试容器

执行命令docker run -it --rm -p 35765:35764 tp-api:v1,会进入容器交互模式,如下:

...

访问量15215 访客数10583