docker-compose实战笔记

docker-compose概念

Docker Compose 是 Docker 官方编排(Orchestration)项目之一,负责快速在集群中部署分布式应用。

教程

本文算不上教程,主要是记录一下个人在这块的实践,防止哪天忘了,翻翻博客还能找的回。不过不排除有人需要详细的成体系的教程,这个放个地址 。

笔记

Gitlab

svn在阿里云,而且磁盘满了有时候都没法提交,备份也没法备份,最后决定把版本控制迁回来,使用git-svn转换以后,最终把svn替换为git。所以要搭建一个gitlab服务器。前任团队的坑。。。
docker-compose.yml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
version: '2'

services:
redis:
restart: always
image: sameersbn/redis:latest
command:
- --loglevel warning
volumes:
- /srv/docker/gitlab/redis:/var/lib/redis:Z

postgresql:
restart: always
image: sameersbn/postgresql:9.5-1
volumes:
- /srv/docker/gitlab/postgresql:/var/lib/postgresql:Z
environment:
- DB_USER=gitlab
- DB_PASS=password
- DB_NAME=gitlabhq_production
- DB_EXTENSION=pg_trgm

gitlab:
restart: always
image: sameersbn/gitlab:8.11.5
depends_on:
- redis
- postgresql
ports:
- "10080:80"
- "10022:22"
volumes:
- /srv/docker/gitlab/gitlab:/home/git/data:Z
environment:
- DEBUG=false

- DB_ADAPTER=postgresql
- DB_HOST=postgresql
- DB_PORT=5432
- DB_USER=gitlab
- DB_PASS=password
- DB_NAME=gitlabhq_production

- REDIS_HOST=redis
- REDIS_PORT=6379

- TZ=Asia/Shanghai
- GITLAB_TIMEZONE=Kolkata

- GITLAB_HTTPS=false
- SSL_SELF_SIGNED=false

- GITLAB_HOST=116.7.245.195
- GITLAB_PORT=10080
- GITLAB_SSH_PORT=10022
- GITLAB_RELATIVE_URL_ROOT=
- GITLAB_SECRETS_DB_KEY_BASE=safausdlfjkj23k4jkljslkdfjlkjasdlkfu8u234ioj23krjlsdfjasdfjkasdfk
- GITLAB_SECRETS_SECRET_KEY_BASE=sadfkljiwfjsnscjksdhfuwehnfnsaldfjh3rhljsdkfjlksajdf
- GITLAB_SECRETS_OTP_KEY_BASE=asfdlaxzcvnhwefhweoicnmcsflncnzmxbvsdajkfasdsdnfkjhsadfj

- GITLAB_ROOT_PASSWORD=edeh123456
- GITLAB_ROOT_EMAIL=que01@foxmail.com

- GITLAB_NOTIFY_ON_BROKEN_BUILDS=true
- GITLAB_NOTIFY_PUSHER=false

- GITLAB_EMAIL=notifications@example.com
- GITLAB_EMAIL_REPLY_TO=noreply@example.com
- GITLAB_INCOMING_EMAIL_ADDRESS=reply@example.com

- GITLAB_BACKUP_SCHEDULE=daily
- GITLAB_BACKUP_TIME=01:00

- SMTP_ENABLED=false
- SMTP_DOMAIN=www.example.com
- SMTP_HOST=smtp.gmail.com
- SMTP_PORT=587
- SMTP_USER=mailer@example.com
- SMTP_PASS=password
- SMTP_STARTTLS=true
- SMTP_AUTHENTICATION=login

- IMAP_ENABLED=false
- IMAP_HOST=imap.gmail.com
- IMAP_PORT=993
- IMAP_USER=mailer@example.com
- IMAP_PASS=password
- IMAP_SSL=true
- IMAP_STARTTLS=false

- OAUTH_ENABLED=false
- OAUTH_AUTO_SIGN_IN_WITH_PROVIDER=
- OAUTH_ALLOW_SSO=
- OAUTH_BLOCK_AUTO_CREATED_USERS=true
- OAUTH_AUTO_LINK_LDAP_USER=false
- OAUTH_AUTO_LINK_SAML_USER=false
- OAUTH_EXTERNAL_PROVIDERS=

- OAUTH_CAS3_LABEL=cas3
- OAUTH_CAS3_SERVER=
- OAUTH_CAS3_DISABLE_SSL_VERIFICATION=false
- OAUTH_CAS3_LOGIN_URL=/cas/login
- OAUTH_CAS3_VALIDATE_URL=/cas/p3/serviceValidate
- OAUTH_CAS3_LOGOUT_URL=/cas/logout

- OAUTH_GOOGLE_API_KEY=
- OAUTH_GOOGLE_APP_SECRET=
- OAUTH_GOOGLE_RESTRICT_DOMAIN=

- OAUTH_FACEBOOK_API_KEY=
- OAUTH_FACEBOOK_APP_SECRET=

- OAUTH_TWITTER_API_KEY=
- OAUTH_TWITTER_APP_SECRET=

- OAUTH_GITHUB_API_KEY=
- OAUTH_GITHUB_APP_SECRET=
- OAUTH_GITHUB_URL=
- OAUTH_GITHUB_VERIFY_SSL=

- OAUTH_GITLAB_API_KEY=
- OAUTH_GITLAB_APP_SECRET=

- OAUTH_BITBUCKET_API_KEY=
- OAUTH_BITBUCKET_APP_SECRET=

- OAUTH_SAML_ASSERTION_CONSUMER_SERVICE_URL=
- OAUTH_SAML_IDP_CERT_FINGERPRINT=
- OAUTH_SAML_IDP_SSO_TARGET_URL=
- OAUTH_SAML_ISSUER=
- OAUTH_SAML_LABEL="Our SAML Provider"
- OAUTH_SAML_NAME_IDENTIFIER_FORMAT=urn:oasis:names:tc:SAML:2.0:nameid-format:transient
- OAUTH_SAML_GROUPS_ATTRIBUTE=
- OAUTH_SAML_EXTERNAL_GROUPS=
- OAUTH_SAML_ATTRIBUTE_STATEMENTS_EMAIL=
- OAUTH_SAML_ATTRIBUTE_STATEMENTS_NAME=
- OAUTH_SAML_ATTRIBUTE_STATEMENTS_FIRST_NAME=
- OAUTH_SAML_ATTRIBUTE_STATEMENTS_LAST_NAME=

- OAUTH_CROWD_SERVER_URL=
- OAUTH_CROWD_APP_NAME=
- OAUTH_CROWD_APP_PASSWORD=

- OAUTH_AUTH0_CLIENT_ID=
- OAUTH_AUTH0_CLIENT_SECRET=
- OAUTH_AUTH0_DOMAIN=

- OAUTH_AZURE_API_KEY=
- OAUTH_AZURE_API_SECRET=
- OAUTH_AZURE_TENANT_ID=

gitlab的docker-compose配置文件其实直接从官方拿过来用的。虽然没什么太大参考价值。不过这里用到了常用的选项,比如restart,image,command,volumes,environment,depends_on。

各个配置项的作用:

  • restart 当容器意外退出后是否自动再次重新启动
  • image 容器镜像
  • command 容器启动后执行的命令
  • volumes 挂载卷,将本地的磁盘目录挂在到容器内 主要做数据备份用
  • environment 环境变量配置
  • depends_on 依赖项,这个配置可以确保依赖服务被配置,但是并不能保证启动顺序

Rap

淘宝的rap是个很不错的东西。前后端分离时候最麻烦的东西就是文档&&文档维护。加上rap本身的数据mock功能,这是一个杀手锏。
rap的docker-compose配置在github上找到一个不错的。srzyhead/rap,不过mysql的配置有点问题导致数据统计没法用,跑过去提了一下pull request。现在没啥问题了,直接git clone回来,按照readme操作即可。

mysql

这个没用到docker-compose,简单的运行了

1
2
mkdir data
docker run --name mysql -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_USER=lyshow -e MYSQL_PASSWORD=123456 -p 3306:3306 -v $(pwd)/data:/var/lib/mysql -d mysql:5.6 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

java项目部署

主要是两个类型的历史项目,一个基于ant打包的,一个是基于maven打包的项目。

ant项目

配置目录:

1
2
3
4
5
.
├── docker-compose.yml
├── server.xml
├── tomcat7
└── wait-for-file.sh

docker-compose.yml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
version: '2'

services:
ant-test:
image: frekele/ant:1.9.7-jdk7
volumes:
- ./tomcat7/:/usr/local/tomcat/:Z
- ../../hotdoc/pc/test/:/data/:Z
entrypoint: |
bash -c "rm -f /data/done && rm -rf /data/WebRoot/WEB-INF/classes && mkdir -p /data/WebRoot/WEB-INF/classes && ant -f /data/build.xml && touch /data/done"

tomcat-test:
image: openweb/oracle-tomcat:7-jre7
command: ["bin/catalina.sh", "run"]
depends_on:
- ant-test-test
entrypoint: /tool/wait-for-file.sh /data/done
ports:
- "9088:800"
volumes:
- ./wait-for-file.sh:/tool/wait-for-file.sh
- ./server.xml:/usr/local/tomcat/conf/server.xml
- ../../hotdoc/pc/test/:/data/:Z

主要是用到了两个服务,一个编译服务,一个tomcat。

server.xml和tomcat7就不说了,主要是项目依赖。主要需要注意的是wait-for-file.sh这个,前面已经说到了,depends_on可以配置依赖项,但是并没有办法确保依赖服务器在主服务就绪前就绪,所以就有了wait-for-file.sh这个东西。
wait-for-file.sh里面东西很简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash

set -e

waitFile="$1"
shift
cmd="$@"

until test -e $waitFile
do
>&2 echo "Waiting for file [$waitFile]."
sleep 1
done

>&2 echo "Found file [$waitFile]."
exec $cmd

主要逻辑就是利用文件的存在来判断是否执行一个操作。这个东西似乎从stackoverflow找到的,非专业只管用就是了。
例子在上面已经有了,entrypoint里面进行wait,然后command里面执行最终要执行的命令。编译服务在启动之前要记住需要删除这个作为flag的done文件。

mvn项目

mvn的项目和ant的是一个思路,一个编译服务,一个tomcat
配置结构:

1
2
3
4
.
├── docker-compose.yml
├── server.xml
└── wait-for-file.sh

docker-compose.yml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
version: '2'

services:
mvn-test-ios:
image: maven:3.2.3-jdk-7u65
volumes:
- ../../../hotdoc/mobile/test_ios:/data/:Z
- ~/.m2/:/root/.m2/
entrypoint: |
bash -c "rm -rf /data/done && cd /data && mvn clean install -Dmaven.test.skip=true && echo '############test_ios mvn clean install is ok ##############' && touch /data/done"

tomcat-test-ios:
image: openweb/oracle-tomcat:7-jre7
command: ["bin/catalina.sh", "run"]
depends_on:
- mvn-test-ios
entrypoint: /tool/wait-for-file.sh /data/done
environment:
- LANG=zh_CN.UTF-8
- TZ=Asia/Shanghai
ports:
- "9001:800"
volumes:
- ./wait-for-file.sh:/tool/wait-for-file.sh
- ./server.xml:/usr/local/tomcat/conf/server.xml
- ../../../hotdoc/mobile/test_ios:/data/:Z

思路和ant的一模一样,只不过编译服务器换成了mvn的,mvn编译时候需要下载过多的依赖,为了省事省时,做了个磁盘映射: ~/.m2/:/root/.m2/ 这样可以高效利用缓存,重启服务器也不会又要再次下载依赖了。

react的项目

以上项目是历史项目,不过最近做了一个完全前后端分离的的react为基础的项目。因为用到了react-router,所以需要对nginx做一些配置才能正常运行。后端的代码依然是基于java的,构建工具是maven。

配置结构:

1
2
3
4
5
.
├── docker-compose.yml
├── nginx.conf
├── server.xml
└── wait-for-file.sh

docker-compose.yml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
version: '2'

services:
mvn-opeartion:
image: maven:3.2.3-jdk-7u65
volumes:
- ../../hotdoc/operation/lyshows:/data/:Z
- ~/.m2/:/root/.m2/
entrypoint: |
bash -c "rm -rf /data/done && cd /data && mvn clean install -Dmaven.test.skip=true && echo '############test_opeartion mvn clean install is ok ##############' && touch /data/done"

tomcat-operation:
image: openweb/oracle-tomcat:7-jre7
command: ["bin/catalina.sh", "run"]
entrypoint: /tool/wait-for-file.sh /data/done
environment:
- LANG=zh_CN.UTF-8
- TZ=Asia/Shanghai
ports:
- "9003:800"
volumes:
- ./wait-for-file.sh:/tool/wait-for-file.sh
- ./server.xml:/usr/local/tomcat/conf/server.xml
- ../../hotdoc/operation/lyshows:/data/:Z

nginx:
image: nginx:stable-alpine
restart: always
ports:
- 7776:8888
- 443:443
links:
- tomcat-operation:backend
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ../../hotdoc/operation/frontEnd/dist:/usr/share/nginx/html/dist

nginx.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
worker_processes 1;

events {
worker_connections 1024;
}

error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;

sendfile on;
#tcp_nopush on;

keepalive_timeout 65;

# 开启gzip
gzip on;

# 启用gzip压缩的最小文件,小于设置值的文件将不会压缩
gzip_min_length 1k;

# gzip 压缩级别,1-10,数字越大压缩的越好,也越占用CPU时间,后面会有详细说明
gzip_comp_level 6;

# 进行压缩的文件类型。javascript有多种形式。其中的值可以在 mime.types 文件中找到。
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;

# 是否在http header中添加Vary: Accept-Encoding,建议开启
gzip_vary on;

server {
listen 8888;
server_name "";
root /usr/share/nginx/html/dist;

gzip_static on;

location / {
try_files $uri $uri/ /index.html;
}

location /api {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://backend:800/;
}
}
}

server.xml是tomcat的配置,这里主要依托后端项目,但是这也不是重点,所以也不贴了。

小结

目前docker和docker-compose主要是用在了公司的开发服务上面,3个月来主要是刚开始gitlab宕机了一次,重启之后数据毫无影响,整体体验还是非常不错的。
而且依托docker,这一套环境在几天之内就完全搭建起来,而且没有污染宿主机器环境,个人感觉非常不错。

遗留问题

docker-compose内部容器访问宿主机器端口尚未找到办法。
PS: 在此文正式发布之前,已经找到了解决方案:那就是external_links选项;但是external_links存在的问题是两个容器之间必须有共通的网络才行,而默认使用docker启动的docker容器似乎是bridge,所以这里需要设置network选项为bridge才行。
当然,说了这么多,如果没有代码其实还是很不好理解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
tomcat-operation:
image: openweb/oracle-tomcat:7-jre7
command: ["bin/catalina.sh", "run"]
entrypoint: /tool/wait-for-file.sh /data/done
network_mode: "bridge"
environment:
- LANG=zh_CN.UTF-8
- TZ=Asia/Shanghai
ports:
- "9003:800"
volumes:
- ./wait-for-file.sh:/tool/wait-for-file.sh
- ./server.xml:/usr/local/tomcat/conf/server.xml
- ../../hotdoc/operation/lyshows:/data/:Z
external_links:
- mysql:mysql

nginx:
image: nginx:stable-alpine
restart: always
network_mode: "bridge"
ports:
- 7776:8888
- 443:443
links:
- tomcat-operation:backend
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ../../hotdoc/operation/frontEnd/dist:/usr/share/nginx/html/dist