本文主要介绍了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/devleeTip: 准备工作到第一步就可以了,因为后续步骤会创建若干目录及文件,如果你想偷懒,不愿意一步一步创建这些目录及文件,可以继续准备工作的后续几步。
-
进入**
工作目录并拉取我的项目**,该项目中拥有一些我们下面操作中需要的文件$ 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 -
添加新的
GPGkey$ 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 upgradeTip:
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 -
启动
dockerdaemon$ sudo service docker start -
验证
docker安装正确$ sudo docker run hello-worldTip: 这个命令会下载一个测试镜像并在容器中运行它,当容器运行时,它会在控制台打印出一条消息,随后便会结束退出。
- 打开以下链接
-
在页面中找到这样的命令并运行
curl -L https://github.com/docker/compose/releases/download/1.8.0-rc2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-composechmod +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-machinechmod +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.crtTip: 生成证书的时候需要格外注意,所有选型除了
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/v2Tip: 目前所搭建的仓库是在主机上进行访问的,可以直接通过
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 startc. 创建扩展证书存放目录
$ sudo mkdir /usr/share/ca-certificates/extrad. 拷贝
主机中的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:443c. 拷贝
主机中的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-shellTip: <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: - sockTip: 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 pushTip: 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 -
创建三台虚拟机
manager1worker1worker2$ 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