Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口
随着Docker近些年越来越流行,在生产环境中也开始有较多人开始使用,Docker技术可以说成为了不得不学习的一门技术。
本文谨记录一下学习笔记,以备以后查阅。
Docker
安装Docker
使用docker官方文档里面写的安装脚本我一直安装失败,就算添加上了dcoker官方源,安装过程也会非常慢,还有一堆教程里让我们使用apt-get安装,这样的确能安装但是版本太老,这里给出一种安装非常简单的方式。
使用阿里的镜像安装
-
可以使用阿里云的镜像仓库下载docker-engine和docker-ce
-
在终端中执行以下命令
curl -sSL http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/internet | sh -
接下来只要等待就好,版本也相对够新。
- 查看docker版本,确认安装成功
在终端中输入如下命令
sudo docker version
出现类似如下结果即为成功
![](https://img.haomeiwen.com/i4433959/063209f104da9be8.png)
- 使用阿里仓库来加速你的docker
可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://dmmxhzvq.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
Dockerfile
Dockerfile定义了容器中内部的环境,访问容器的网络资源和磁盘在容器是完全与外部隔离的,所以必须将你需要使用的端口映射到外部世界,并指出需要复制到该环境中的文件。
说白了Dockerfile就是一个定义容器中环境的配置文件。。
我们在这里创建一个简单的flask项目作为例子。
编写第一个Docker APP
- 创建一个空的文件夹,在里面创建一个文件为Dockerfile,其中的内容为
Dockerfile为:
# Use an official Python runtime as a parent image
# 使用python3.5的官方镜像作为基础镜像(可以按需要更改)
FROM python:3.5-slim
# Set the working directory to /app
# 设置工作目录
WORKDIR /app
# Copy the current directory contents into the container at /app
# 复制当前目录下的内容到容器的/app目录下(Dockerfile同级所有目录)
ADD . /app
# Install any needed packages specified in requirements.txt
# 安装项目所需要的依赖文件requirements.txt
RUN pip install -r requirements.txt
# Make port 80 available to the world outside this container
# 让80端口能在容器外部访问
EXPOSE 80
# Define environment variable
# 定义环境便令
ENV NAME World
# Run app.py when the container launches
# 在容器启动时,运行python app.py
CMD ["python", "app.py"]
- flask项目的app.py为:
from flask import Flask
from redis import Redis, RedisError
import os
import socket
# Connect to Redis
redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2)
app = Flask(__name__)
@app.route("/")
def hello():
try:
visits = redis.incr("counter")
except RedisError:
visits = "<i>cannot connect to Redis, counter disabled</i>"
html = "<h3>Hello {name}!</h3>" \
"<b>Hostname:</b> {hostname}<br/>" \
"<b>Visits:</b> {visits}"
return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname(), visits=visits)
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80)
这里作为例子,只给出最简单的代码。
注:host一定要填0.0.0.0 因为这是在容器内,本机访问的127.0.0.1 和容器内不是一回事。
- 收集项目依赖的库,在终端输入
$ pip freeze > requirements.txt
以上执行完目录结构应该如下所示:
![](https://img.haomeiwen.com/i4433959/d0fbfc140bb1f7d5.png)
构建APP
在编写好了你的app和Dockerfile之后,我们就可以使用Docker构建app
在终端输入docker build命令,
$ docker bulid -t docker-flask-demo .
注:
- 如果你的系统没有将当前用户放入docker组中,请在命令前加上sudo
- -t 命令是给你的镜像起一个友好的名字
- 在这句命令的末尾还有一个".",代表当前目录的意思
等待上述命令完成就可以在终端执行docker images命令查看构建好的镜像
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
earthchen/docker-flask-demo part1 3964297abb1f About an hour ago 212MB
运行app
由于Dockerfile中的EXPOSE 80命令,容器向外只开发80端口,我们需要将外部空闲端口映射到容器的80端口
使用-p帮我们绑定端口,在终端中输入一下命令
$ docker run -p 4000:80 docker-flask-demo
在浏览器访问127.0.0.1:4000后如图
![](https://img.haomeiwen.com/i4433959/5f89bf7d20f4e89e.png)
注: 如果需要使当前容器运行在后台,需要使用-d选项,即:
$ docker run -d -p 4000:80 docker-flask-demo
加上-d命令之后,当前只会有容器id输出,需要查看容器情况,需要使用docker ps命令
$ docker ps
或者
$ docker container ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5762ccf1dd1c earthchen/docker-flask-demo:part1 "python app.py" 27 seconds ago Up 26 seconds 0.0.0.0:4000->80/tcp infallible_neumann
如果想停止运行的容器,使用docker stop命令,后面接容器id
$ docker stop 5762ccf1dd1c
或者
$ docker container stop 5762ccf1dd1c
5762ccf1dd1c
如果想删除镜像或者容器,需要先停止运行的容器,
删除容器的命令为docker rm或者是docker container rm
删除镜像的命令为docker rmi或者是docker image rm
分享你的镜像
我这里使用的是阿里云的docker Hub,如果你选择的是其他的镜像库,请自行查阅相关介绍
登录到阿里云docker registry
$ sudo docker login --username=15555000826 registry.cn-hangzhou.aliyuncs.com
给需要分享的镜像打上标签
$ sudo docker tag 5762ccf1dd1c registry.cn-hangzhou.aliyuncs.com/earthchen/docker-flask-demo:part1
将本地镜像推到仓库
$ sudo docker push registry.cn-hangzhou.aliyuncs.com/earthchen/docker-flask-demo:part1
拉取镜像
在需要部署的机器上拉取镜像,
$ docker pull registry.cn-hangzhou.aliyuncs.com/earthchen/docker-flask-demo:part1
part1: Pulling from earthchen/docker-flask-demo
ad74af05f5a2: Already exists
0a004373a9cb: Already exists
92b2e8511724: Already exists
bc1149958e59: Already exists
2e7ebaf17b77: Already exists
71c4b9e65b72: Pull complete
b668a32a73d0: Pull complete
1e87b99f6998: Pull complete
Digest: sha256:3b4b74a0e273a26fff42eddc077bccfb9963fd552aad766b93dc524a66c5f455
Status: Downloaded newer image for registry.cn-hangzhou.aliyuncs.com/earthchen/docker-flask-demo:part1
拉取完成之后就可以运行容器
$ docker run -p 4000:80 registry.cn-hangzhou.aliyuncs.com/earthchen/docker-flask-demo:part1
docker-compose.yml
编写第一个docker-compose.yml
docker-compose.yml的位置可以随意放置,一般放在项目根目录,
本例的docker-compose.yml的为:
version: "3"
services:
web:
# replace username/repo:tag with your name and image details
image: registry.cn-hangzhou.aliyuncs.com/earthchen/docker-flask-demo:part1
deploy:
# 运行5个镜像实体
replicas: 5
resources:
limits:
# 每个实体分配10%的cpu
cpus: "0.1"
# 每个实体分配50m内存
memory: 50M
restart_policy:
# 如果容器失败,立即重启
condition: on-failure
ports:
# 将外部4000端口映射到容易内80端口
- "4000:80"
networks:
# Web容器共享端口80通过负载均衡的网络控制
# 用默认的设置定义控制网络(这是一个负载均衡的覆盖网络)。
- webnet
networks:
webnet:
运行你的负载均衡app
在我们运行docker stack deploy之前时,我们需要运行以下命令
docker swarm init
不过不先执行上述命令,会产生错误
运行过后,我们就可以执行deploy命令了,我们需要给app起一个新的名字,在哪这里我们使用getstartedlab
$ docker stack deploy -c docker-compose.yml getstartedlab
Creating network getstartedlab_webnet
Creating service getstartedlab_web
运行完上述命令,就会有5个容器启动,我们可以查看一下
$ docker stack ps getstartedlab
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
qg7mox0vrwu1 getstartedlab_web.1 docker-flask-demo:latest earthchen-CP65S Running Running 25 seconds ago
n7kb3qedrryx getstartedlab_web.2 docker-flask-demo:latest earthchen-CP65S Running Running 27 seconds ago
04tr7rp7euet getstartedlab_web.3 docker-flask-demo:latest earthchen-CP65S Running Running 27 seconds ago
z7yh0tvvrpwj getstartedlab_web.4 docker-flask-demo:latest earthchen-CP65S Running Running 26 seconds ago
z01zvjtneg3r getstartedlab_web.5 docker-flask-demo:latest earthchen-CP65S Running Running 24 seconds ago
如果使用的是*docker ps同样能看到5个容器正在运行,只是显示的没有上述命令详细
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bccc38eb8429 docker-flask-demo:latest "python app.py" 18 seconds ago Up 16 seconds 80/tcp getstartedlab_web.1.qg7mox0vrwu1ucnh6g79pnkuc
368fabab2f5b docker-flask-demo:latest "python app.py" 18 seconds ago Up 15 seconds 80/tcp getstartedlab_web.5.z01zvjtneg3rj8f5lsi9kzkwn
b34a7b9f73e6 docker-flask-demo:latest "python app.py" 19 seconds ago Up 17 seconds 80/tcp getstartedlab_web.2.n7kb3qedrryxx3odog4t47hzq
746425e5bc36 docker-flask-demo:latest "python app.py" 19 seconds ago Up 17 seconds 80/tcp getstartedlab_web.3.04tr7rp7euetg182oe43p6j4k
887874b4edab docker-flask-demo:latest "python app.py" 19 seconds ago Up 16 seconds 80/tcp getstartedlab_web.4.z7yh0tvvrpwju15zqwbgic1gx
集群操作app
你可以批量的更改这些容器的参数,更改docker-compose.yml中的参数后,执行docker stack deploy命令
$ docker stack deploy -c docker-compose.yml getstartedlab
Updating service getstartedlab_web (id: n94rdcq09p07hro5sqh1tjhou)
image docker-flask-demo:latest could not be accessed on a registry to record
its digest. Each node will access docker-flask-demo:latest independently,
possibly leading to different nodes running different
versions of the image.
docker将会自动帮我们更新配置,我们不需要杀死容器,
如果我们不需要这个app了,我们可以使用docker stack rm删除
$ docker stack rm getstartedlab
Removing service getstartedlab_web
Removing network getstartedlab_webnet
这将删除getstartedlabapp,但是节点群仍然存在,并且仍然在运行
相关常用命令
docker stack ls # List all running applications on this Docker host
docker stack deploy -c <composefile> <appname> # Run the specified Compose file
docker stack services <appname> # List the services associated with an app
docker stack ps <appname> # List the running containers associated with an app
docker stack rm <appname> # Tear down an application
集群
设置你的集群
首先我们需要安装一下virtualbox和docker-machine
- 安装docker-machine到linux
$ curl -L https://github.com/docker/machine/releases/download/v0.12.2/docker-machine-`uname -s`-`uname -m` >/tmp/docker-machine &&
chmod +x /tmp/docker-machine &&
sudo cp /tmp/docker-machine /usr/local/bin/docker-machine
- 安装docker-machine,不然会没有virtualbox驱动
自行浏览virtualbox网站下载
创建一组虚拟机使用docker-machine,使用VirtualBox驱动
$ docker-machine create --driver virtualbox myvm1
$ docker-machine create --driver virtualbox myvm2
创建好了使用docker-machine ls命令查看一下虚拟机
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
myvm1 - virtualbox Running tcp://192.168.99.101:2376 v17.06.1-ce
myvm2 - virtualbox Running tcp://192.168.99.100:2376 v17.06.1-ce
打开系统中的virtualbox也能看到正在运行两个虚拟机,分别名为myvm1和myvm2
![](https://img.haomeiwen.com/i4433959/85c90409d662272f.png)
接下来,我们应该发送命令到您的虚拟机myvm1,使其作为成为一个群组管理,发送命令使用docker-machine ssh,设置群组管理的命令为docker swarm init,所以最后的命令应该为:
$ docker-machine ssh myvm1 "docker swarm init"
注:一般都会遇到以下问题,如果遇到了请使用以下方法解决
Error response from daemon: could not choose an IP address to advertise since this system has multiple addresses on different interfaces (10.0.2.15 on eth0 and 192.168.99.101 on eth1) - specify one with --advertise-addr exit status 1
- 使用docker-machine ls查看虚拟主机信息,记住myvm1的ip地址
- 重新使用docker-machine ssh运行docker swarm init命令,并使用该ip地址和端口连接
$ docker-machine ssh myvm1 "docker swarm init --advertise-addr 192.168.99.101:2376"
Swarm initialized: current node (rgo0wk88oxw0sx2iynnfrq7ni) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-0kkgpn8xkux6fr6e3fyqg3414vrkh9x73ho1tjiljtw201d6dj-2p65t277az7rj8yg5idss1i1q 192.168.99.101:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
注:末尾端口一定是2377,刚开始我想当然以为是不是我的环境不一样,查看了虚拟机的ip是2376,创建集群管理是可以成功的,但是其他结点加入集群就会失败。注意:
- 端口2377
- 端口2377
- 端口2377,重要的事情说三遍
看到输出如上,就是成功了。表示我们已经在虚拟机myvm1创建了一个集群,并设置为管理
可以看到,响应docker swarm init包含一个预先配置的 docker swarm join命令,您可以在要添加的任何节点上运行。复制此命令,并将其发送到myvm2 docker-machine ssh把myvm2 加入您的新群组作为工作人员:
$ docker-machine ssh myvm2 "docker swarm join --token SWMTKN-1-0kkgpn8xkux6fr6e3fyqg3414vrkh9x73ho1tjiljtw201d6dj-2p65t277az7rj8yg5idss1i1q 192.168.99.101:2377"
This node joined a swarm as a worker.
这样就创建好了一个集群
接下来,我们可以在myvm1上使用docker node ls命令查看结点,首先我们需要使用docker-macheine ssh命令登录myvm1虚拟机
$ docker-macheine ssh
## .
## ## ## ==
## ## ## ## ## ===
/"""""""""""""""""\___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\_______/
_ _ ____ _ _
| |__ ___ ___ | |_|___ \ __| | ___ ___| | _____ _ __
| '_ \ / _ \ / _ \| __| __) / _` |/ _ \ / __| |/ / _ \ '__|
| |_) | (_) | (_) | |_ / __/ (_| | (_) | (__| < __/ |
|_.__/ \___/ \___/ \__|_____\__,_|\___/ \___|_|\_\___|_|
Boot2Docker version 17.06.1-ce, build HEAD : 80114bc - Fri Aug 18 17:58:04 UTC 2017
Docker version 17.06.1-ce, build 874a737
docker@myvm1:~$
然后在虚拟机myvm1中执行docker node ls命令查看结点
docker@myvm1:~$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
0b7ae42ny8506cwe2rvt3sxqy myvm2 Ready Active
26kzc37prtj7vlgk7tmc4lq5y * myvm1 Ready Active Leader
退出虚拟机的终端只需要执行exit即可
docker@myvm1:~$ exit
如果不想直接进入虚拟机输入指定在退出呢,可以直接使用docker-machine ssh "你的命令",这样也是可以的
在集群上部署app
使用scp命令将docker-compose.yml复制到集群管理虚拟机myvm1的主目录中
$ docker-machine scp docker-compose.yml myvm1:~
在集群管理虚拟机myvm1中在集群中部署你的app,使用docker stack deploy -c docker-compose.yml getstartedlab命令
$ docker-machine ssh myvm1 "docker stack deploy -c docker-compose.yml getstartedlab"
然后就会自动部署你的应用在myvm1和myvm2上了。
我们可以在myvm1上查看容器运行的情况
$docker@myvm1:~$ docker stack ps getstartedlab
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
2d0nk6cdzk9s getstartedlab_web.1 registry.cn-hangzhou.aliyuncs.com/earthchen/docker-flask-demo:part1 myvm2 Running Preparing 59 seconds ago
0k5x3z8kzy3c getstartedlab_web.2 registry.cn-hangzhou.aliyuncs.com/earthchen/docker-flask-demo:part1 myvm1 Running Running 58 seconds ago
741qhp1gjrd0 getstartedlab_web.3 registry.cn-hangzhou.aliyuncs.com/earthchen/docker-flask-demo:part1 myvm2 Running Preparing 59 seconds ago
xar5o0a86xqd getstartedlab_web.4 registry.cn-hangzhou.aliyuncs.com/earthchen/docker-flask-demo:part1 myvm1 Running Running 58 seconds ago
uondlmb3agae getstartedlab_web.5 registry.cn-hangzhou.aliyuncs.com/earthchen/docker-flask-demo:part1 myvm2 Running Preparing 59 seconds ago
可以看到容器分布在两个虚拟机上。
注:如果你要使用集群,那各集群主机必须开放以下指定端口
- 端口7946用于容器网络发现的TCP / UDP。
- 端口4789 UDP用于容器入口网络
如果你要更改你的应用,你可以更改集群管理虚拟机myvm1中的docker-compose.yml,或者更改代码。
在这些情况下,只需要在myvm1中执行docker stack deploy再次部署即可
如果有新机器需要加入集群,只需要使用docker swarm join加入该集群即可
如何离开集群
- 如果非管理机要离开集群,只需要执行docker-machine ssh myvm2 "docker swarm leave"
- 如果是管理机,那需要强制执行,离开集群后也会同时删除该集群docker-machine ssh myvm1 "docker swarm leave --force"
注:
- ddocker Version: 17.05.0-ce
- docker-machine version 0.12.2, build 9371605
- 上述环境在ubuntu16.04 lts中搭建测试成功
- 上述文字皆为个人看法,如有错误或建议请及时联系我
网友评论