通过学习Docker官网Get Started文档,把使用过程和碰到的问题记录下来,以备后面回顾。
本文不会涉及到Docker源码和架构设计方面的知识,单纯是docker常用命令的使用。
一.安装docker
docker目前有两个版本一个是Community Edition(CE)社区版,另一个是Enterprise Edition(EE)企业版,社区版是免费的,企业版是付费的,企业版每个版本有更长的维护期,有更多的官方插件支持,基础功能与社区版是一样的,选择社区版就足够一般企业的应用,如果有二次开发能力的企业,也可以基于社区版做扩展。
访问https://www.docker.com/community-edition,下载对应操作系统的版本,我在自己的Mac上安装了docker,因此下面的操作都是基于Mac操作系统,如果你使用的是windows系统请自行查看官网文档。
运行下载的docker安装文件(Docker.dmg),安装完成之后,在应用里面会有Docker图标:
image.png
可以通过命令行工具,执行docker命令来监测安装是否成功,下面在命令行运行一个docker官方仓库里面hello-world镜像(image):
docker run hello-world
image.png
首先docker会从官方仓库里面搜索hello-world镜像文件,下载到本地,创建一个容器装载这个镜像文件,容器启动之后,执行镜像进行文件的入口程序,输出上面的"Hello from Docker!"到终端。说明docker已经安装成功!
二、docker 基础命令
- 查看本地镜像
刚才我们从docker官方仓库下载了hello-world镜像(image)文件,可以使用下面命令查看本地仓库的镜像文件:
docker images
或者
docker image ls
image.png
- 查看docker版本信息
docker version
image.png
- 查看docker详细信息
docker info
image.png
三、定义一个docker容器的环境
某一个docker容器内安装什么样的环境依赖库和工具,可以在名称为Dockerfile文件中定义,在启动docker容器时,docker容器依据Dockerfile中的定义,安装环境依赖、 应用程序和启动应用/服务。
Dockerfile 样例:
# Use an official Python runtime as a parent image
FROM python:2.7-slim
# Set the working directory to /app
WORKDIR /app
# Copy the current directory contents into the container at /app
ADD . /app
# Install any needed packages specified in requirements.txt
RUN pip install --trusted-host pypi.python.org -r requirements.txt
# Make port 80 available to the world outside this container
EXPOSE 80
# Define environment variable
ENV NAME World
# Run app.py when the container launches
CMD ["python", "app.py"]
这里不多说了,可以自行查看官方文档查看Dockerfile定义说明(https://docs.docker.com/engine/reference/builder/)。
上面Dockerfile中涉及到两个文件:requirements.txt和app.py,requirements.txt是需要安装的python依赖包,app.py最终要启动的应用程序。
requirements.txt 样例:
Flask
Redis
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)
保证上面三个文件(Dockerfile,requirements.txt和app.py)在同一目录下面,例如目录为docker-apps。
四、编译应用构建本地应用镜像
$ cd docker-apps
$ ls
Dockerfile app.py requirements.txt
编译应用构建镜像
#-t 参数格式为镜像名称:标签,如果省略标签,默认标签为latest,
#标签常常用来区别某一应用不同版本.
docker build -t friendlyhello .
#注意不要遗漏上面命令后面的点
$ docker images
#在本地仓库内查看到刚刚编译的应用镜像
REPOSITORY TAG IMAGE ID
friendlyhello latest 326387cea398
五、运行应用镜像
docker run -d -p 4000:80 friendlyhello
#-d开关表示后台运行容器应用
#-p端口映射转发,本机通过4000端口访问docker容器80端口.
在浏览器中访问http://localhost:4000
六、常用容器管理命令
- 查看本地运行的容器
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
866312776dcf friendlyhello "python app.py" 45 seconds ago Up 43 seconds 0.0.0.0:4000->80/tcp cocky_goodall
- 停止某个运行的容器
docker container stop 866312776dcf
#或
docker container stop cocky_goodall
- 进入container内部
docker exec -it 866312776dcf bash
#或
docker exec -it cocky_goodall bash
#可以指定账户进入container内部
docker exec -u root -it cocky_goodall bash
七、云端镜像仓库
除了docker官方提供的云端镜像仓库外,还有第三方的镜像仓库,如阿里云的容器镜像服务,网易的云服务docker镜像服务,我用的是阿里云的,目前免费,注册一个阿里云账号,访问容器Hub服务。
为什么要用第三方镜像仓库,docker官方镜像仓库在国外,下载镜像很慢,有可能下载失败。
- 默认官方镜像仓库使用方法
docker run hello-world
刚刚运行的hello-world应用镜像,就是在docker官方云端仓库上。如果要把自己的本地应用镜像推送到云端仓库,以后可以随处随地通过网络获取应用镜像。
首先需要在docker官网(https://cloud.docker.com/)注册一个账号,注册好账号,在本地可以通过命令行登录。
docker login
#输入Docker账号ID和密码
之后为刚刚的friendlyhello本地镜像生成一个新的标签,标签的命名要注意,jcalvin为docker账号ID,get-started为repository名称,part2为标签的名称,之前说过标签常常用来区分应用镜像的版本.
$ docker tag friendlyhello jcalvin/get-started:part2
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
friendlyhello latest d9e555c53008 3 minutes ago 195MB
jcalvin/get-started part2 d9e555c53008 3 minutes ago 195MB
python 2.7-slim 1c7128a655f6 5 days ago 183MB
...
把本地应用镜像推送到云端镜像仓库.
docker push jcalvin/get-started:part2
这个时候可以访问https://cloud.docker.com,查看云端仓库是否推送成功.
到此我们就可以在其他服务器上来运行存储在云端仓库中的应用镜像了.
docker run -p 4000:80 jcalvin/get-started:part2
#这个时候你可能有一个疑问,为什么运行hello-world时不需要指定仓库账号和标签?
#首先hello-world是官方云端仓库里的,这个应用镜像不属于某一个账号,因此不需要指定
#标签如果不指定,默认为latest.
- 阿里云容器Hub服务使用方法
首先在阿里云(https://account.aliyun.com/register/register.htm)上注册一个账号,注册过程就不说了。登录阿里云后,访问阿里云docker容器仓库产品(https://cr.console.aliyun.com)。首先会引导你开通云端仓库的命名空间(区别不同角色的,例如个人名称空间、公司名称空间或者是团队名称空间),我创建个人名称空间jcalvin。
在管理操作里面设置访问权限为公开,也可以设置为私有,如果设置为私有,每次运行仓库上面的镜像应用,需要首先docker login登录到阿里云仓库,根据自己的安全级别来设置.
image.png
本地命令行登录阿里云docker仓库
docker login --username=阿里云账号名称 registry.cn-beijing.aliyuncs.com
#registry.cn-beijing.aliyuncs.com为阿里云仓库云端地址,
#可以从阿里云官网获得,有引导教程。
#本地重新依据friendlyhello镜像生成一个新的镜像
docker tag friendlyhello registry.cn-beijing.aliyuncs.com/jcalvin/get-started:part2
#推送到阿里云应用镜像仓库
docker push registry.cn-beijing.aliyuncs.com/jcalvin/get-started:part2
- 阿里云镜像加速器
阿里云把docker官方仓库做了一个镜像,此镜像不是docker image的意思,是仓库的镜像,方便国内用户获取docker官方应用镜像。访问地区为https://cr.console.aliyun.com/#/accelerator,依据阿里云官方教程配置。
下面是我在Mac本上面配置方法:
点击docker的Preferences,选择Daemon标签页,在Registry mirrors中添加阿里云镜像加速器专有地址(每个阿里云账号的专有地址不同,请填写自己的地址)
image.png
在命令行查看是否已经添加成功:
docker info
image.png
Registry Mirrors和上面添加的配置相同,说明设置成功了.
八、Docker Services和Swarm
docker service是能够提供相同服务的一组container组成,例如网站中获取用户基本信息的服务,就可以由一组container来提供,为什么要用多个container来提供相同的服务?这是为了解决访问负载均衡的问题,比较有的服务需要承接大量请求,如果只由一个container来承接,必然会导致请求超时或请求队列堆积的问题。Docker是通过Services来支持Load Balance的。
在使用docker service之前,需要使用docker三大工具之一swarm(蜂群),swarm是一个docker容器所在节点(服务器)的集群,这个集群节点分为两种角色,一个是manager,另一个是worker,manager角色的节点负责管理整个集群,worker节点负责提供具体服务。想了解详细的swarm原理和使用,请查看官方文档。
现在有一个问题,如果我只有一台机器,怎么去模拟多个服务器节点,使用swarm集群那? 答案就是在机器上安装虚拟机,运行多个虚拟机实例,模拟多个台机器。
我使用的是Oracle Virtualbox虚拟机,访问https://www.virtualbox.org/wiki/Downloads下载对应操作系统的Virtualbox版本。下载完成后安装,具体安装步骤请参考Oracle Virtualbox官网。
虚拟机中使用什么系统,如何安装docker环境?这个要使用boot2docker,boot2docker是基于 Tiny Core Linux 的轻量级Linux发行版,专为 Docker准备,完全运行于内存中,24M大小,启动仅5-6秒。
请已经自己的操作系统和docker版本来下载boot2docker,下载地址为http://boot2docker.io/。下载如果很慢,可以使用迅雷下载。安装之后,我们就可以使用Virtualbox来开启多个虚拟机实例。
docker提供了创建虚拟机的工具docker-machine,可以直接通过命令来创建虚拟机。下面我们创建三个虚拟机实例,分别为myvm1、myvm2和myvm3。
docker-machine create --engine-registry-mirror=https://xxxx.mirror.aliyuncs.com --driver virtualbox myvm1
docker-machine create --engine-registry-mirror=https://xxxxx.mirror.aliyuncs.com --driver virtualbox myvm2
docker-machine create --engine-registry-mirror=https://xxxx.mirror.aliyuncs.com --driver virtualbox myvm3
参数说明:
--engine-registry-mirror=https://xxxx.mirror.aliyuncs.com表示虚拟机中的docker使用的远程仓库加速镜像地址,我用的是阿里云的加速镜像仓库,可以不用这个参数设置,但在国内网络还是建议设置上。
--driver virtualbox 指定虚拟机驱动为virtualbox
myvm1 指定虚拟机实例名称为myvm1
三个虚拟机实例创建完成之后,可以通过Virtualbox查看。
image.png image.png
上图左侧菜单栏中,看到刚刚创建的三个虚拟机实例,并处以运行状态,表明创建成功。
也可以通过命令行来查看,运行的三个实例。
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
myvm1 * virtualbox Running tcp://192.168.99.100:2376 v17.10.0-ce
myvm2 - virtualbox Running tcp://192.168.99.101:2376 v17.10.0-ce
myvm3 - virtualbox Running tcp://192.168.99.102:2376 v17.10.0-ce
- 操作虚拟机实例三种方式
1、可以通过docker-machine进行虚拟机实例系统.
docker-machine ssh myvm1
image.png
现在已经登录到myvm1虚拟机实例中了,boot2docker系统是一个精简版的linux系统,所以缺少一些常用的linux命令和工具。
2、通过docker-machine执行内部命令
docker-machine ssh myvm1 "docker container ls"
#查看myvm1上的容器
3、通过docker-machine设置环境变量
$ docker-machine env myvm1
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.100:2376"
export DOCKER_CERT_PATH="/Users/calvin/.docker/machine/machines/myvm1"
export DOCKER_MACHINE_NAME="myvm1"
# Run this command to configure your shell:
# eval $(docker-machine env myvm1)
运行上面最后一行,设置环境变量。
$ eval $(docker-machine env myvm1)
这个时候,docker任何命令都会认为是对myvm1虚拟机实例上的执行。
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
w3ufe6vt5c6srjgbn3rrtempm * myvm1 Ready Active Leader
3d656umnct4bkw7wkd6lqqp60 myvm2 Ready Active
is4de0qm3c4dyj7bk7qsutcm3 myvm3 Ready Active
这里提前运行了swarm集群,在manager节点上查看集群节点情况,验证这个docker node ls命令是在myvm1运行的结果。
目前任何docker命令都是默认在myvm1上执行,那么如何取消这种设置?修改本机环境变量就OK了.
$ docker-machine env -u
unset DOCKER_TLS_VERIFY
unset DOCKER_HOST
unset DOCKER_CERT_PATH
unset DOCKER_MACHINE_NAME
# Run this command to configure your shell:
# eval $(docker-machine env -u)
运行最后一句命令.
eval $(docker-machine env -u)
- 启动Swarm集群
首先选择一个服务器节点作为manager节点角色,在上面初始化swarm集群。这里使用myvm1实例作为manager节点,进行初始化工作。
#docker-machine ls 查看myvm1的公开IP地址
$ docker-machine ssh myvm1 "docker swarm init --advertise-addr 192.168.99.100"
# 命令上输出集群的token(令牌),其他节点需要通过这个令牌才能加入到集群中
$ docker-machine ssh myvm2 "docker swarm join --token SWMTKN-1-4fwugp2xvlhu2jc5spzl1r1oqpbkq7lemk0uipmchw0a1ije9v-93381i59qtihok0ebqwpoejfy 192.168.99.100:2377"
$ docker-machine ssh myvm3 "docker swarm join --token SWMTKN-1-4fwugp2xvlhu2jc5spzl1r1oqpbkq7lemk0uipmchw0a1ije9v-93381i59qtihok0ebqwpoejfy 192.168.99.100:2377"
如果要添加一个manager角色的节点,可以在swarm集群上manager节点上执行下面命令:
docker@myvm1:~$ docker swarm join-token manager
To add a manager to this swarm, run the following command:
docker swarm join --token SWMTKN-1-4fwugp2xvlhu2jc5spzl1r1oqpbkq7lemk0uipmchw0a1ije9v-6yjgnpa8bwncjafr1c405wwzx 192.168.99.100:2377
把上面输出中含有token的命令行,在新的节点上执行,把新的节点作为manager角色添加到swarm集群。
docker-machine create --engine-registry-mirror=https://m7s5bskp.mirror.aliyuncs.com --driver virtualbox myvm4
docker-machine ssh myvm4
docker@myvm4:~$ docker swarm join --token SWMTKN-1-4fwugp2xvlhu2jc5spzl1r1oqpbkq7lemk0uipmchw0a1ije9v-6yjgnpa8bwncjafr1c405wwzx 192.168.99.100:2377
This node joined a swarm as a manager.
#退出 myvm4实例终端
docker@myvm4:~$ exit
查看集群节点情况:
$ docker-machine ssh myvm1
docker@myvm1:~$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
w3ufe6vt5c6srjgbn3rrtempm * myvm1 Ready Active Leader
3d656umnct4bkw7wkd6lqqp60 myvm2 Ready Active
is4de0qm3c4dyj7bk7qsutcm3 myvm3 Ready Active
kmspopqr6zsqqa7t72lggyjd1 myvm4 Ready Active Reachable
可以看到有两个manager角色的节点。
九、Swarm集群中启动服务
上面讲过Docker Service是一组具有相同服务的container,我们可以通过Swarm来部署服务。
Docker service需要通过docker-compose.yml文件中定义服务使用的应用镜像、容器资源大小、容器数量和端口映射等信息。
下面是一个docker-compose.yml文件,其中有两个服务,名称分别为web和visualizer。
web服务应用镜像位置registry.cn-beijing.aliyuncs.com/jcalvin/get-started:part2,部署5个container,每个container内存大小为50M,CPU占用整个节点的10%,端口映射为80:80。
visualizer服务应用镜像位置dockersamples/visualizer:stable,默认部署1个container,部署在manager节点上,端口映射为8080:8080。
version: "3"
services:
web:
# replace username/repo:tag with your name and image details
image: registry.cn-beijing.aliyuncs.com/jcalvin/get-started:part2
deploy:
replicas: 5
restart_policy:
condition: on-failure
resources:
limits:
cpus: "0.1"
memory: 50M
ports:
- "80:80"
networks:
- webnet
visualizer:
image: dockersamples/visualizer:stable
ports:
- "8080:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
placement:
constraints: [node.role == manager]
networks:
- webnet
networks:
webnet:
- 启动服务
docker-machine env myvm1
eval $(docker-machine env myvm1)
# 设置环境变量后,执行的docker命令相当于在myvm1上执行的命令
# 已经docker-compose.yml中的服务定义,部署名称为getstartedlab的服务组(服务栈),getstartedlab可以根据自己的情况来命名。
$ docker stack deploy -c docker-compose.yml getstartedlab
# 查看部署的服务
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
wu5cgwublapc getstartedlab_visualizer replicated 1/1 dockersamples/visualizer:stable *:8080->8080/tcp
ny1zooiw9r75 getstartedlab_web replicated 5/5 registry.cn-beijing.aliyuncs.com/jcalvin/get-started:part2 *:80->80/tcp
# 查看有哪些服务栈
$ docker stack ls
NAME SERVICES
getstartedlab 2
# 查看myvm1上面的container
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
30c6331fa9dc registry.cn-beijing.aliyuncs.com/jcalvin/get-started:part2 "python app.py" 24 hours ago Up 24 hours 80/tcp getstartedlab_web.2.mzcqct66bhaqk4y8saygdxkd0
0708d923bfb7 registry.cn-beijing.aliyuncs.com/jcalvin/get-started:part2 "python app.py" 24 hours ago Up 24 hours 80/tcp getstartedlab_web.5.xkt1p1dv6c0q0d63bvd2r28z7
09bf0a2b56b2 registry.cn-beijing.aliyuncs.com/jcalvin/get-started:part2 "python app.py" 24 hours ago Up 24 hours 80/tcp getstartedlab_web.4.atd5ye0o6xk5bxlfjqh2si0m1
41ed5b9714a1 registry.cn-beijing.aliyuncs.com/jcalvin/get-started:part2 "python app.py" 24 hours ago Up 24 hours 80/tcp getstartedlab_web.1.zpyf1uiqtqofrd57pgc57jqcd
23cd5d04bd8b registry.cn-beijing.aliyuncs.com/jcalvin/get-started:part2 "python app.py" 24 hours ago Up 24 hours 80/tcp getstartedlab_web.3.r9jtgi8iooxnungkg15e5x8p4
c6beeddf381d dockersamples/visualizer:stable "npm start" 24 hours ago Up 24 hours 8080/tcp getstartedlab_visualizer.1.gr9tava2njt46z31q8ppebzsm
上面docker-compose.yml定义了一个visualizer服务,这是一个swarm集群可视化页面,可以通过在浏览器访问http://192.168.99.100:8080/,查看swarm集群情况。
image.png
访问web名称服务http://192.168.99.100
image.png- 删除存在的服务栈
$ docker stack ls
NAME SERVICES
getstartedlab 2
$ docker stack rm getstartedlab
Removing service getstartedlab_visualizer
Removing service getstartedlab_web
Removing network getstartedlab_webnet
- 删除创建的虚拟机实例
$ eval $(docker-machine env -u)
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
myvm1 virtualbox Timeout
myvm2 - virtualbox Running tcp://192.168.99.101:2376 v17.10.0-ce
myvm3 - virtualbox Running tcp://192.168.99.102:2376 v17.10.0-ce
myvm4 - virtualbox Running tcp://192.168.99.103:2376 v17.10.0-ce
# 依次删除虚拟机实例
$ docker-machine rm myvm4
About to remove myvm4
WARNING: This action will delete both local reference and remote instance.
Are you sure? (y/n): y
Successfully removed myvm4
$ docker-machine rm myvm3
$ docker-machine rm myvm2
$ docker-machine rm myvm1
网友评论