注: 个人感觉 Digitalocean 在国内访问要快些, Docker 环境和云厂商,硬件等无关,可以选择自己的喜欢的,
用这个链接申请 Digitalocean account, 可获赠 10 https://m.do.co/c/333996b27f07
- yum install -y yum-utils
- yum-config-manager \
- --add-repo \
- https://download.docker.com/linux/centos/docker-ce.repo
- yum install docker-ce
- systemctl start docker
docker run hello-world
- firewall-cmd --add-port=22/tcp --permanent
- firewall-cmd --add-port=2376/tcp --permanent
- firewall-cmd --add-port=2377/tcp --permanent
- firewall-cmd --add-port=7946/tcp --permanent
- firewall-cmd --add-port=7946/udp --permanent
- firewall-cmd --add-port=4789/udp --permanent
- firewall-cmd --reload
systemctl restart docker
Worker Node(node02, node03)
- firewall-cmd --add-port=22/tcp --permanent
- firewall-cmd --add-port=2376/tcp --permanent
- firewall-cmd --add-port=7946/tcp --permanent
- firewall-cmd --add-port=7946/udp --permanent
- firewall-cmd --add-port=4789/udp --permanent
- firewall-cmd --reload
systemctl restart docker
sample output:
Swarm initialized: current node (4i3ohjjyai0rbhovfd9hlx33l) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join \
–token SWMTKN-1-16k4hp7o6kwnq2jp1wxfz93tnfah2n215sjzqiecq3aw5nip1c-80eukvhe1m2fcgzf6t5giefkq \
x.x.x.x:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
}}}
- docker swarm join \
- --token <YOUR-Token>\
- x.x.x.x:2377
注:如果 manager node 上运行 swarm init 后的输出找不到了,用下面命令查询 token
查询要增加 manager node 的 token:
docker swarm join-token -q manager
查询要增加 worker node 的 token:
docker swarm join-token -q worker
- [root@node01 ~]# docker node ls
- ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
- hgqkuckwzvzayafro1rcj0ep9 node03 Ready Active
- idyj2pllz9s4f07jceh6iz7zs node02 Ready Active
- tkbdrvy6tebf0tc0idcb9dusb * node01 Ready Active Leader
[root@node01 ~]# docker service ls
ID NAME MODE REPLICAS IMAGE
rc15revna8a9 nginx replicated 2/2 nginx
[root@node01 ~]# docker service ps nginx
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
x3gx6ea7z88p nginx.1 nginx:latest node03 Running Running 10 seconds ago
4ywabc9s1qrh nginx.2 nginx:latest node02 Running Running 10 seconds ago
}}}
两个 nginx 容器分别运行在 node02, node03
测试访问
- [root@node01 ~]# curl http://node02
- <!DOCTYPE html>
- <html>
- <head>
- <title>Welcome to nginx!</title>
- <style>
- body {
- width: 35em;
- margin: 0 auto;
- font-family: Tahoma, Verdana, Arial, sans-serif;
- }
- </style>
- </head>
- <body>
- <h1>Welcome to nginx!</h1>
- <p>If you see this page, the nginx web server is successfully installed and
- working. Further configuration is required.</p>
- <p>For online documentation and support please refer to
- <a href="http://nginx.org/">nginx.org</a>.<br/>
- Commercial support is available at
- <a href="http://nginx.com/">nginx.com</a>.</p>
- <p><em>Thank you for using nginx.</em></p>
- </body>
- </html>
[root@node01 ~]# curl http://node03
[root@node01 ~]# curl http://node01
访问 node01,node02, node3 会看到相同的输出结果, 尽管我们的两个 nginx container 只在 node02, node03 上, 并没有在 node01 上运行, Swarm cluster routing mesh 起了作用
Delete test service:
docker service rm nginx
var port=process.env.WEBAPP_PORT||8000;
www.listen (port,function(){
console.log("Server is listening port:"+port);
});
}}}
vi Dockerfile
- FROM node:7-alpine
- WORKDIR /app
- COPY app/webapp.js /app
- ENV WEBAPP_PORT=8000 \
- NODE_ENV=production
- EXPOSE $WEBAPP_PORT
- CMD node webapp.js
docker build -t webapp-handson-01:v1 .
把 image push 到 docker hub 或者私有的 image registry
[root@node01 compose]# docker service create --name webapp --replicas 3 -p 80:8000 webapp-handson-01:v1
e61n4hxny5m8fvry6o2jqqrc6
[root@node01 compose]# docker service ls
ID NAME MODE REPLICAS IMAGE
e61n4hxny5m8 webapp replicated 3/3 webapp-handson-01:v1
[root@node01 compose]# docker service ps webapp
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
gz0278r4fgt9 webapp.1 webapp-handson-01:v1 node03 Running Running 11 seconds ago
ezpm3tlg5atd webapp.2 webapp-handson-01:v1 node02 Running Running 11 seconds ago
oi3ozukwnv13 webapp.3 webapp-handson-01:v1 node01 Running Running 11 seconds ago
}}}
Version 1.0
Hello Docker!
Hostname: f811da71f4c5
Version 1.0
Hello Docker!
Hostname: f81c55047bfc
Version 1.0
Hello Docker!
Hostname: dbb8bc1da943
Version 1.0
Hello Docker!
Hostname: f811da71f4c5
}}}
开启另一个 shell, curl http://node01/kill , 执行两次
查看第一个 shell 窗口, webapp response 的 hostname 发生了变化,从 3 个变 1 个,然后很快又变成 3 个
- [root@node01 compose]# docker service ps webapp
- ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
- 3tn76hcllj4o webapp.1 webapp-handson-01:v1 node03 Running Running about a minute ago
- kwjggesesvqx webapp.2 webapp-handson-01:v1 node01 Running Running 2 seconds ago
- i8ybpo3btsmw \_ webapp.2 webapp-handson-01:v1 node01 Shutdown Complete 7 seconds ago
- k0g41z6b2h1d webapp.3 webapp-handson-01:v1 node02 Running Running 7 seconds ago
- 0bgp2fb8k4n9 \_ webapp.3 webapp-handson-01:v1 node02 Shutdown Complete 12 seconds ago
观察第一个 shell webapp response 的变化,response page 来自不同的 hostname, 从 3 个变为 5 个
- docker service scale webapp=5
- docker service scale webapp=3
- docker service update webapp --image webapp-handson-01:v2
观察第一个 shell webapp response 和 docker service ps webapp 的输出,在服务不中断的情况下,从 version 1 滚动升级为 Version 2。
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
pnrz6cy53j9z webapp.1 webapp-handson-01:v2 node03 Running Running 39 seconds ago
3tn76hcllj4o \_ webapp.1 webapp-handson-01:v1 node03 Shutdown Shutdown 39 seconds ago
spnp7yv1wt81 webapp.2 webapp-handson-01:v2 node01 Running Running 15 seconds ago
kwjggesesvqx \_ webapp.2 webapp-handson-01:v1 node01 Shutdown Shutdown 15 seconds ago
i8ybpo3btsmw \_ webapp.2 webapp-handson-01:v1 node01 Shutdown Complete 3 minutes ago
rfzi5lrz92uf webapp.3 webapp-handson-01:v2 node02 Running Running 27 seconds ago
k0g41z6b2h1d \_ webapp.3 webapp-handson-01:v1 node02 Shutdown Shutdown 27 seconds ago
0bgp2fb8k4n9 \_ webapp.3 webapp-handson-01:v1 node02 Shutdown Complete 3 minutes ago
docker node update --availability active node02
node 重新 active 后, 以前的 container 并不会 move 回来。
再次 Scale up webapp
docker service scale webapp=4
actived node 开始接受新的创建 replica 的请求.
如何让 web app 只运行在指定的一组 node 上面
可以通过在 node 上面加 label, 然后更新或者增加 constraint 到 service 来完成; Label 分为 engine.labels 和 node.labels, engine.labels 是在 node docker daemon 启动时增加 option --label key=value, example --label group=QA 完成 label node 的。而 node.labels 可以随时动态增加到 node 上面.
示例:
- docker node update --label-add disklabel=fast node02
- docker node update --label-add disklabel =fast node03
- docker service update --constraint-add 'node.labels.disklabel ==fast' webapp
- docker service ps webapp
- docker service update --constraint-add engine.labels.group==QA webapp
var express = require('express');
var redis = require('redis');
var app = express();
var redisHostName = process.env.DBNAME||'redisdb';
var redisClient = redis.createClient(process.env.REDIS_PORT||'6379', redisHostName);
redisClient.on('connect', function(err,reply) {
if (err) {
console.log('Failed to connect Redis server:'+err);
}else{
console.log('Connected to Redis server'); }
});
var version = '***** 1.0 *****';
var hostname = require("os").hostname();
app.get('/', function (req, res) {
redisClient.incr('counter', function(err, count) {
if(err) console.log(err);
console.log('version:'+ version + 'hostname:'+hostname);
res.send("\nWebApp Version:"+version+"\nHostname:"+
hostname +"\nTotal Reviews:"+ count + "\n" );
});
});
app.get('/kill', function (req, res) {
process.exit();
});
var port = process.env.WEBAPP_PORT||8000;
var server = app.listen(port, function() {
console.log('Server listening on port' + server.address().port);
});
}}}
Dockerfile
- FROM node:7-alpine
- WORKDIR /app
- COPY app/package.json /app
- RUN npm install
- COPY app/ /app
- ENV WEBAPP_PORT=8000 \
- NODE_ENV=production \
- DBNAME=redisdb
- EXPOSE $WEBAPP_PORT
- CMD ["node", "webapp.js"]
docker build -t webapp-handson-02:v1 .
push image 到 docker hub 或者自己的 image repository
docker network create --driver overlay mynet
docker service create --replicas 1 --network mynet --name redisdb redis
docker service create --replicas 3 --network mynet --name webapp -p 80:8000 webapp-handson-02:v1
webapp 通过 Docker 内置的 DNS 名字访问后端 redisdb
- while true;
- do curl http: //node03; sleep 1; done
- version: "3"
- services:
- redisdb:
- image: redis:latest
- ports:
- - 6379
- networks:
- - myappnet
- deploy:
- placement:
- constraints: [node.role == manager]
- mywebapp:
- image: YOURNAME/webapp-handson-02:v1
- ports:
- - 80:8000
- environment:
- DBNAME: redisdb
- networks:
- - myappnet
- depends_on:
- - redisdb
- deploy:
- replicas: 3
- labels: [APP=MYWEBAPP]
- # placement constraint - in this case on 'worker' nodes only
- placement:
- constraints: [node.role == worker]
- networks:
- myappnet:
部署 yml 文件
查看 stack
可以直接更改 webapp.yml 里面的 image, replicas 等信息再重新执行 stack deploy, 同样可以完成 scale, rolling update 等功能。
YAML 其他配置
可以在 YAML 里面设置 service resource limits, restart, update policy 等。示例:
resources:
# Hard limit - Docker does not allow to allocate more
limits:
cpus: '0.25'
memory: 512M
# Soft limit - Docker makes best effort to return to it
reservations:
cpus: '0.25'
memory: 256M
# service restart policy
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
# service update configuration
update_config:
parallelism: 1
delay: 10s
failure_action: continue
monitor: 60s
max_failure_ratio: 0.3
# service resource management end
YAML 文件规范参考:
https://docs.docker.com/compose/compose-file/
来源: http://www.tuicool.com/articles/AFZZJzv