本文主要介绍了Docker在Ubuntu上的主要应用,并详细的阐述了实现步骤、遇到的问题及问题的解决方案。新手可以先了解一下它们,老鸟可以直接跳过下面的若干步骤,废话不多说,开始吧~
明确目标很关键,我们的主要目标就是基于Docker来完成以下工作
建立私有的gitlab
建立私有的docker registry
通过gitlab-ci来自动化build,test,push,deploy我们的项目
利用集群部署我们的服务
系统软件:
- ubuntu 16.04 LTS
- docker 1.12
- docker compose 1.8.0-rc2
- docker machine 0.8.0-rc2
名词解释:
- 主机 : 安装ubuntu的机器,可以是物理机也可以是虚拟机
- 主机ip :
主机
的ip,可通过ifconfig
命令获取
- 其他主机 : 安装有Docker的其他
主机
- docker0 : Docker服务默认创建的网桥名
- <username> : 你的用户名,我这里使用自己的用户名devlee
- 工作目录 :
主机
上进行本文描述的相关工作的工作目录
- 我的项目 : 我把这篇文章中涉及的代码总结于此项目
相关说明:
- 大多数命令需要root权限,可以通过以下命令来解决每次都需要sudo的步骤
$ sudo -i
工作目录:
- /work/<username>
我的项目:
-
创建好
工作目录
$ sudo mkdir /work/devlee
Tip: 准备工作到第一步就可以了,因为后续步骤会创建若干目录及文件,如果你想偷懒,不愿意一步一步创建这些目录及文件,可以继续准备工作的后续几步。
-
进入**
工作目录
并拉取我的项目
**,该项目中拥有一些我们下面操作中需要的文件$ sudo cd /work/devlee && git clone https://github.com/devlee/docker-aio.git
-
将项目中src中的所有文件夹拷贝至**
工作目录
**下$ sudo cp -r /work/devlee/docker-aio/src /work/devlee
-
此时查看**
工作目录
,应该拥有gitlab
,registry
,machine
**等文件夹
-
在
主机
上使用root
权限或sudo
命令来执行以下命令 -
打开一个
terminal
-
更新包信息,确保
APT
使用https
方式工作且安装了CA
证书$ sudo apt-get update
$ sudo apt-get install apt-transport-https ca-certificates
-
添加新的
GPG
key$ sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
-
使用你最喜欢的编辑器来打开以下文件,不存在则创建它
/etc/apt/sources.list.d/docker.list
- 清空所有已经存在的
entry
,并添加一条新的entry
deb https://apt.dockerproject.org/repo ubuntu-xenial main
- 保存并关闭该文件
Tip:
5
,6
和7
这三个步骤可以通过以下命令实现sh -c "echo deb https://apt.dockerproject.org/repo ubuntu-xenial main > /etc/apt/sources.list.d/docker.list"
-
更新
APT
包索引$ sudo apt-get update
-
如果存在则先卸载旧有版本
$ sudo apt-get purge lxc-docker
-
验证
APT
从正确的仓库中拉取$ sudo apt-cache policy docker-engine
-
执行以下命令,获取软件最新版本
$ sudo apt-get upgrade
Tip:
upgrade
命令会更新所有软件包
-
在
主机
上打开一个terminal
-
更新包管理器
$ sudo apt-get update
-
安装推荐的包
$ sudo apt-get install linux-image-extra-$(uname -r)
-
在
主机
上使用sudo
-
更新
APT
包索引$ sudo apt-get update
-
安装
docker
$ sudo apt-get install docker-engine
-
启动
docker
daemon$ sudo service docker start
-
验证
docker
安装正确$ sudo docker run hello-world
Tip: 这个命令会下载一个测试镜像并在容器中运行它,当容器运行时,它会在控制台打印出一条消息,随后便会结束退出。
- 打开以下链接
-
在页面中找到这样的命令并运行
curl -L https://github.com/docker/compose/releases/download/1.8.0-rc2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
- 打开以下链接
- 在页面中找到这样的命令并运行
curl -L https://github.com/docker/machine/releases/download/v0.8.0-rc2/docker-machine-`uname -s`-`uname -m` >/usr/local/bin/docker-machine
chmod +x /usr/local/bin/docker-machine
-
执行以下命令
docker version
得到
docker
的版本信息,包括客户端
和服务端
Client: Version: 1.12.0 API version: 1.24 Go version: go1.6.3 Git commit: 8eab29e Built: Thu Jul 28 22:11:10 2016 OS/Arch: linux/amd64 Server: Version: 1.12.0 API version: 1.24 Go version: go1.6.3 Git commit: 8eab29e Built: Thu Jul 28 22:11:10 2016 OS/Arch: linux/amd64
-
执行以下命令
docker-compose version
得到
docker compose
当前版本信息,包括py
,ssl
等信息docker-compose version 1.8.0-rc2, build c72c966 docker-py version: 1.9.0-rc2 CPython version: 2.7.9 OpenSSL version: OpenSSL 1.0.1e 11 Feb 2013
-
执行以下命令
docker-machine version
得到
docker machine
当前版本信息docker-machine version 0.8.0-rc2, build 4ca1b85
-
进入**
工作目录
,创建文件夹gitlab
**,并进入该目录$ sudo cd /work/devlee && mkdir gitlab && cd gitlab
-
创建docker-compose.yml,并将以下链接中的代码拷贝至该文件中
https://raw.githubusercontent.com/sameersbn/docker-gitlab/master/docker-compose.yml Tip: 与我的项目中的文件内容有些许差异,主要是镜像版本号和容器
container_name
的定义
-
执行以下命令
$ sudo docker-compose up -d
-
搭建完成,访问以下地址进行初始化并重置
root
密码
Tip:
- 这里的
registry
版本为v2
,隶属于docker distribution
项目,项目地址为:https://github.com/docker/distribution
- 我们同时会利用
nginx
来实现https
仓库
- 我们会使用
docker-registry-frontend
来作为web前端展示
-
进入**
工作目录
,创建文件夹registry
**,并进入该目录$ sudo cd /work/devlee && mkdir registry && cd registry
-
创建docker-compose.yml文件,并写入以下代码
version: '2' services: nginx: restart: always image: 'nginx:latest' ports: - 443:443 links: - registry:registry volumes: - ./nginx/:/etc/nginx/conf.d container_name: 'docker-registry-proxy' registry: restart: always image: 'registry:2.4.1' ports: - 5000:5000 environment: - REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/data volumes: - ./data:/data container_name: 'docker-registry' frontend: restart: always image: 'konradkleine/docker-registry-frontend:v2' ports: - 8080:80 environment: - ENV_DOCKER_REGISTRY_HOST=nginx - ENV_DOCKER_REGISTRY_PORT=443 - ENV_DOCKER_REGISTRY_USE_SSL=1 links: - nginx:nginx container_name: 'docker-registry-frontend'
-
创建文件夹data和nginx,并进入nginx文件夹
$ sudo mkdir data && mkdir nginx && cd nginx
-
创建registry.conf文件,并写入以下代码
upstream docker-hub { server registry:5000; } server { listen 443; server_name localhost; # SSL ssl on; ssl_certificate /etc/nginx/conf.d/docker-registry.crt; ssl_certificate_key /etc/nginx/conf.d/docker-registry.key; # disable any limits to avoid HTTP 413 for large image uploads client_max_body_size 0; # required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486) chunked_transfer_encoding on; location /v2/ { # Do not allow connections from docker 1.5 and earlier # docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" ) { return 404; } # To add basic authentication to v2 use auth_basic setting plus add_header auth_basic "registry.localhost"; auth_basic_user_file /etc/nginx/conf.d/docker-registry.htpasswd; add_header 'Docker-Distribution-Api-Version' 'registry/2.4.1' always; proxy_pass http://docker-hub; proxy_set_header Host $http_host; # required for docker client's sake proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 900; } }
-
生成
ssl
证书$ sudo openssl req -x509 -nodes -newkey rsa:2048 -keyout /work/devlee/registry/nginx/docker-registry.key -out /work/devlee/registry/nginx/docker-registry.crt
Tip: 生成证书的时候需要格外注意,所有选型除了
CN
都可以选择默认,这个选项需要输入仓库的域名,由于我们是本地内网所以输入docker-registry
,记得要在其他主机的/etc/hosts
中添加解析,通过ifconfig
命令可以查看主机
的ip
-
安装
htpasswd
$ sudo apt-get install apache2-utils
-
创建用户名密码,这里用户名是
devlee
,第一个用户需要添加-c
参数$ sudo htpasswd -c /work/devlee/registry/nginx/docker-registry.htpasswd devlee
-
启动服务
$ sudo cd /work/devlee/registry && docker-compose up -d
-
搭建完成,访问以下地址进行验证,登录后会返回
{}
https://localhost:443/v2
Tip: 目前所搭建的仓库是在主机上进行访问的,可以直接通过
localhost
访问,要在其他主机
上访问仓库,需要其他主机
配置有证书/work/devlee/registry/nginx/docker-registry.crt
,且需要设置/etc/hosts
(别名访问),通过域名或别名进行访问,https://docker-registry:443/v2
-
在
其他主机
上配置证书 (内网配置,如果仓库在外网,不用配置hosts) a. 配置/etc/hosts
,假设主机ip
为10.12.30.52
,写入10.12.30.52 docker-registry
b. 启动Docker服务
$ sudo service docker start
c. 创建扩展证书存放目录
$ sudo mkdir /usr/share/ca-certificates/extra
d. 拷贝
主机
中的docker-registry.crt
文件至上述目录e. 注册证书
$ sudo dpkg-reconfigure ca-certificates
-
在
其他主机
上配置证书(方法2) a. 配置/etc/hosts
,假设主机ip
为10.12.30.52
,写入10.12.30.52 docker-registry
b. 创建目录
$ sudo cd /etc/docker && mkdir cert.d && cd cert.d && mkdir docker-registry:443
c. 拷贝
主机
中的docker-registry.crt
文件至上述最后一个创建的目录d. 重启Docker服务
$ sudo service docker restart
-
推送测试
$ sudo docker tag hello-world docker-registry:443/hello $ sudo docker push docker-registry:443/hello
-
向
/work/devlee/gitlab/docker-compose.yml
添加以下代码runner-docker-in-docker: restart: always image: sameersbn/gitlab-ci-multi-runner:latest depends_on: - gitlab volumes: - /srv/docker/gitlab-runner/docker-in-docker:/home/gitlab_ci_multi_runner/data links: - gitlab:gitlab environment: - CI_SERVER_URL=http://<gitlab-ip>:10080/ci - RUNNER_TOKEN=<gitlab-token> - RUNNER_DESCRIPTION=docker-in-docker-runner - RUNNER_EXECUTOR=docker - DOCKER_IMAGE=docker:latest - DOCKER_PRIVILEGED=true - DOCKER_EXTRA_HOSTS=localhost:<registry-ip> container_name: gitlab-runner-docker-in-docker runner-docker-socket-binding: restart: always image: sameersbn/gitlab-ci-multi-runner:latest depends_on: - gitlab volumes: - /srv/docker/gitlab-runner/docker-socket-binding:/home/gitlab_ci_multi_runner/data - /var/run/docker.sock:/var/run/docker.sock - /git/devlee/registry/nginx/volumes:/etc/docker/cert.d links: - gitlab:gitlab environment: - CI_SERVER_URL=http://<gitlab-ip>:10080/ci - RUNNER_TOKEN=<gitlab-token> - RUNNER_DESCRIPTION=docker-socket-binding-runner - RUNNER_EXECUTOR=docker - DOCKER_IMAGE=docker:latest - DOCKER_EXTRA_HOSTS=localhost:<registry-ip> - DOCKER_VOLUMES=/git/devlee/registry/nginx/volumes:/etc/docker/cert.d container_name: gitlab-runner-docker-socket-binding extra_hosts: - "localhost:172.17.0.1" - "docker-registry:172.17.0.1" runner-shell: restart: always image: sameersbn/gitlab-ci-multi-runner:latest depends_on: - gitlab volumes: - /srv/docker/gitlab-runner/shell:/home/gitlab_ci_multi_runner/data links: - gitlab:gitlab environment: - CI_SERVER_URL=http://<gitlab-ip>:10080/ci - RUNNER_TOKEN=<gitlab-token> - RUNNER_DESCRIPTION=shell-runner - RUNNER_EXECUTOR=shell container_name: gitlab-runner-shell
Tip: <gitlab-ip>: 私有的gitlab服务ip,由于我们是搭建在容器里的,所以这里取
主机
的docker0
的ip
<gitlab-token>: 这里的token可以填gitlab上某个项目的special token
,也可以是shared token
,我这里用的是shared token
,使用admin
账户登录gitlab,访问loalhost:10080/admin/runners
就可以看到token <registry-ip>: 私有的registry服务ip,由于我们是搭建在容器里的,所以这里取主机
的docker0
的ip
-
启动服务
$ sudo cd /work/devlee/gitlab && docker-compose up -d
-
打开gitlab,使用admin账户登录,在runners页面中给这三个runner添加tag,分别为
docker
,sock
,shell
-
用
admin
账户在gitlab
上新建一个koa-app
项目 -
进入
工作目录
,创建文件夹dev
,并进入该目录 -
拷贝我们的项目至本地
$ sudo git clone http://localhost:10080/root/koa-app.git
-
进入我们的项目目录
$ sudo cd koa-app
-
安装
npm
$ sudo apt-get install python-software-properties $ sudo add-apt-repository ppa:gias-kay-lee/npm $ sudo apt-get update $ sudo apt-get install npm
-
创建
package.json
$ sudo npm init
-
安装
koa2
$ sudo npm install koa@2 --save
-
创建
index.js
,代码如下const Koa = require('koa') const app = new Koa app.use(ctx => { ctx.body = 'Hello, Docker' }) app.listen(3232)
-
创建
.dockerignore
,内容如下.git
.gitlab-ci.yml
README.md
-
创建
.gitignore
,内容如下node_modules
-
创建
.gitlab-ci.yml
,内容如下image: docker:latest before_script: - docker version build:image stage: build script: - docker login -u devlee -p xxxx localhost:443 - docker build -t localhost:443/devlee/koa-app:latest . - docker push localhost:443/devlee/koa-app:latest tags: - sock
Tip: xxxx是创建用户
devlee
时输入的密码 -
创建
Dockerfile
,内容如下FROM localhost:443/devlee/node:latest COPY . /devlee/ WORKDIR /devlee/ RUN npm install CMD ["node", "index"] EXPOSE 3232
-
提交代码到gitlab
$ sudo git add --all $ sudo git commit -m "xxxx" $ sudo git fetch $ sudo git rebase $ sudo git push
Tip: xxxx是提交的修改注释
-
由于提交的代码中包含了.gitlab-ci.yml文件,会自动触发ci相关任务。
-
我们利用虚拟机当集群节点,所以需要安装
virtualbox
$ sudo sh -c "echo deb http://download.virtualbox.org/virtualbox/debian xenial contrib > /etc/apt/sources.list" $ sudo wget -q https://www.virtualbox.org/download/oracle_vbox_2016.asc -O- | sudo apt-key add - $ sudo wget -q https://www.virtualbox.org/download/oracle_vbox.asc -O- | sudo apt-key add - $ sudo apt-get update $ sudo apt-get install virtualbox-5.1
-
创建三台虚拟机
manager1
worker1
worker2
$ sudo docker-machine create -d virtualbox manager1 $ sudo docker-machine create -d virtualbox worker1 $ sudo docker-machine create -d virtualbox worker2
-
创建swarm及manager
$ sudo docker-machine ssh manager1 $ sudo docker swarm init --advertise-addr <MANAGER-IP>
-
创建worker1和worker2,分别ssh到worker1及worker2执行以下命令,该命令在上条命令执行后会展示
$ sudo docker swarm join --token <token> <MANAGER-IP>:2377
-
登录虚拟机manager1(worker1/2,三个节点都执行一遍6-11操作)
$ sudo docker-machine ssh manager1 $ sudo docker-machine ssh worker1 $ sudo docker-machine ssh worker2
-
在
/etc/hosts
文件中加入registry
的解析
192.168.99.1 docker-registry
Tip:
192.168.99.1
是registry
所在主机
的vboxnet0
的ip,也就是主机相对于虚拟机能访问到的ip地址
-
创建
/etc/docker/certs.d/docker-registry:443/docker-registry.crt
文件,写入和之前搭建私有的gitlab中的crt文件内容即可 -
重启docker服务
$ sudo /etc/init.d/docker stop $ sudo /etc/init.d/docker start
-
测试登录registry
$ sudo docker login docker-registry:443
-
查询registry中的image信息
$ curl --cacert /etc/docker/certs.d/docker-registry:443/docker-registry.crt --basic --user devlee:<password> https://docker-registry:443/v2/_catalog
Tip:
<password>是创建用户devlee时输入的密码,以上命令执行后,应该可以看到我们的koa-app
{"repositories":["devlee/koa-app"]}
-
拉取koa-app的镜像
$ sudo docker pull docker-registry:443/devlee/koa-app:latest
-
回到
主机
登录集群管理节点创建一个服务$ sudo docker-machine ssh manager1 $ sudo docker service create --replicas 1 --name koa-app docker-registry:443/devlee/koa-app:latest
-
查看服务
$ sudo docker service ls $ sudo docker service inspect --pretty koa-app $ sudo docker service ps koa-app
-
扩展服务
$ sudo docker service scale koa-app=3
-
我们利用虚拟机当集群节点,所以需要安装
virtualbox
$ sudo sh -c "echo deb http://download.virtualbox.org/virtualbox/debian xenial contrib > /etc/apt/sources.list" $ sudo wget -q https://www.virtualbox.org/download/oracle_vbox_2016.asc -O- | sudo apt-key add - $ sudo wget -q https://www.virtualbox.org/download/oracle_vbox.asc -O- | sudo apt-key add - $ sudo apt-get update $ sudo apt-get install virtualbox-5.1
-
创建一台虚拟机用作kv store服务器
$ sudo docker-machine create -d virtualbox consul-kv-store
-
登录kv store服务器环境,并启动服务
$ sudo eval $(docker-machine env consul-kv-store) $ sudo docker run -d --name=consul --restart=always -p "8500:8500" -h "consul" progrium/consul -server -bootstrap
-
创建swarm-master
$ sudo docker-machine create \ -d virtualbox \ --swarm --swarm-master \ --swarm-discovery="consul://$(docker-machine ip consul-kv-store):8500" \ --engine-opt="cluster-store=consul://$(docker-machine ip consul-kv-store):8500" \ --engine-opt="cluster-advertise=eth1:2376" \ swarm-master
-
创建swarm-node-01
$ sudo docker-machine create \ -d virtualbox \ --swarm --swarm-discovery="consul://$(docker-machine ip consul-kv-store):8500" \ --engine-opt="cluster-store=consul://$(docker-machine ip consul-kv-store):8500" \ --engine-opt="cluster-advertise=eth1:2376" \ swarm-node-01
-
创建swarm-node-02
$ sudo docker-machine create \ -d virtualbox \ --swarm --swarm-discovery="consul://$(docker-machine ip consul-kv-store):8500" \ --engine-opt="cluster-store=consul://$(docker-machine ip consul-kv-store):8500" \ --engine-opt="cluster-advertise=eth1:2376" \ swarm-node-02
-
登录虚拟机swarm-master(node-01/02),三个节点都执行一遍8-10操作)
$ sudo docker-machine ssh swarm-master $ sudo docker-machine ssh swarm-node-01 $ sudo docker-machine ssh swarm-node-02
-
在
/etc/hosts
文件中加入registry
的解析
192.168.99.1 docker-registry
Tip:
192.168.99.1
是registry
所在主机
的vboxnet0
的ip,也就是主机相对于虚拟机能访问到的ip地址
-
创建
/etc/docker/certs.d/docker-registry:443/docker-registry.crt
文件,写入和之前搭建私有的gitlab中的crt文件内容即可 -
重启docker服务
$ sudo /etc/init.d/docker stop $ sudo /etc/init.d/docker start
-
登录swarm-master管理节点创建overlay网络devlee-net
$ sudo eval $(docker-machine env --swarm swarm-master) docker network create --driver overlay --subnet=10.0.9.0/24 devlee-net
-
登录docker-registry并拉取koa-app
$ sudo docker login docker-registry:443 $ docker pull docker-registry:443/devlee/koa-app:latest
-
在/work/devlee/machine目录下新建docker-compose.yml
version: '2' services: koa-app: image: docker-registry:443/devlee/koa-app:latest ports: - '13232:3232'
-
启动koa-app
$ sudo docker-compose up -d
-
此时通过docker ps命令可以发现集群中的某一台机器运行了koa-app
-
扩展服务至集群所有机器(可能会有错误,因为该服务占用了特定的端口)
$ sudo docker-compose scale koa-app=3
-
集群部署服务koa-app
通过scope为swarm的overlay类型网络ingress
ingress overlay swarm
-
集群部署服务koa-app(方法2)
通过scope为global的overlay类型网络devlee-net
devlee-net overlay global
-
Example
在主机1和主机2的容器1和容器2中部署应用1和应用2,此时应用1和应用2可以相互访问各自内容,网络名即上面的ingress或devlee-net
docker run -itd --name=容器1 --network=网络名 --env="constraint:node==机器1" 应用1 docker run -itd --name=容器2 --network=网络名 --env="constraint:node==机器2" 应用2