为了解决环境配置的难题,囊括操作系统的设置,各种库和组件的安装。避免自家软件只能在自家的机器上跑起来:
解决办法:
- 虚拟机: 虽然可以通过虚拟机还原软件的原始环境,但是缺点也很多,比如资源占用问题,启动时间长等问题。
- Linux容器: 不是模拟一个完整的操作系统,而是隔离进程,容器里面的进程接触到的资源都是虚拟出来的。
Vagrant和Docker都是虚拟化技术:Vagrant是基于virtualbox的虚拟机构建的开发环境,但是Docker是继续LXC的轻量级容器虚拟技术
Docker属于对于Linux容器的一种封装,直接调用容器的接口即可
它是一个使用Go语言编写的基于Linux的容器,一次封装,到处运行。
它将应用以及应用所需要的东西打包成一个文件,运行这个文件即可生成整个虚拟容器。
Docker的三大用途:
- 提供一次性的环境,提供单元测试和构建的环境
- 云服务,容器可以随时关闭与开启
- 微服务架构,可以使用多个容器运行多个服务 **微服务思想:**软件把任务外包出去,让各种外部服务完成这些任务,软件本身只是底层服务的调度中心和组装层。
安装运行Docker:
我这里直接使用 sudo apt install docker.io
进行安装
运行Docker命令的时候,需要确保本机起了Docker服务:
sudo service docker start
或者 sudo systemctl start docker
这里注意Docker命令需要sudo权限,所以把用户加入Docker用户组,这样可以避免每次输入sudo:
sudo usermod -aG docker $USER
然后需要把计算机logout 然后login一下
查看Docker的基本信息:
PS C:\Windows\system32\WindowsPowerShell\v1.0> docker info
Containers: 1
Running: 1
Paused: 0
Stopped: 0
Images: 4
image镜像文件:
Docker把应用以及应用的依赖全部打包到image文件里面 所以通过image文件,可以直接生成Docker容器。
image文件相当于容器的模板,Docker根据这个模板生成一个容器实例,所以可以通过image文件生成多个同时运行的实例。
可以列出本机所有的image文件: docker image ls
也可以删除某个image文件: docker image rm [name]
image文件制作后可以上传到网上的仓库,Docker有一个官方的仓库为Docker Hub。
但是国内访问Docker的速度很慢,所以需要把仓库的网址改成国内的镜像网站:
打开/etc/default/docker文件,然后加上:
DOCKER_OPTS="--registry-mirror=https://registry.docker-cn.com"
然后重启Docker服务: sudo service docker restart
运行一个简单的容器实例:
将image文件抓取到本地: docker image pull library/hello-world
Docker官方提供的image文件都是放在library这个组里面的
然后运行这个image文件:docker container run hello-world
这个docker container run 具有找不到指定文件就会自动抓取的功能
有些容器不会自动终止,因为提供的是服务,所以需要手动终止:
docker container kill [containID]
由于image文件生成的容器实例也是一个容器文件,所以容器生成后,一共两个文件:image文件和容器文件
列出正在运行的container: docker container ls
列出本机所有的container:docker container ls --all
这个生成的是containerID,关闭容器也是需要这个ID
删除容器: docker container rm [ID]
有用的命令:
docker container start [containerID] #用来启动已有的停止运行的容器
docker container stop [containerID] #用于终止容器运行
docker container logs [containerID] #用于查看Docker容器的输出
docker container exec -it [containerID] /bin/bash #用于进入一个正在运行的容器
docker container cp [containID]:[/path/to/file] . #用于从正在进行的容器里面将文件拷贝到本机
docker run image_name
:直接启动一个本地的image,如果不存在会去官方仓库里面下载
docker images
:列出本地所有的images
docker ps -a
:列出所有的container包括已经退出的container
docker rm container_id
:删除一个container
docker rmi image_id/image_name
:删除一个image
docker commit
:将一个container制作成一个image
docker stop container_id
:退出当前的container
!!!docker run -i -t debian:stretch /bin/bash
:进入容器的交互系统,-t
是启动终端,-i
是允许交互
docker start containerid
:启动容器
docker attach containerid
:进入在后台运行的容器
docker stop $(docker ps -a -q)
:停止所有的容器
docker rm $(docker ps -a -q)
:删除所有的容器
AUFS:理解Docker的关键
Advanced Union File System 就是把不同物理位置的目录合并mount到同一个目录中,docker把一个镜像分成了很多层,这些层合并在一起才成为了一个完整的image.这样子ubuntu15.04跟ubuntu16.04的image可能只有一点点差别.这点差别体现在第四层layer上.那么ubuntu15.04跟16.04就可以共享前三层layer.这样子如果你本地有了ubuntu15.04的image.那么再pull ubuntu16.06的时候只要把第四层的pull下来就可以了。
这里还有另一个问题,pull一个image,启动了container,然后把该装的软件都install了,退出这个container就表明之前安装的东西全没了,这个时候我们需要使用commit命令,这个命令把当前的可写层合并到image的只读层里面,这样image相当与多了一层,一个image本身就是由好几层只读层layer构建成的,当相对于一个image启动一个容器的时候,只会在image的只读层上添加一个可写层,然后所有在容器中的操作都仅仅反应在容器的层面上。
在我们使用docker rm container_id的时候只是删掉了这个容器的一层可写层数据,只读层是image和container共享的,所以只要image没有被删除,只读层就一定不会被删掉。
多个image共享多个只读层的情况下,删掉一个image只代表删掉了这个image独有的一层只读层数据,其他的数据并不会被影响。
制作image的基础办法就是: 在一个container中配置好所有东西,然后使用commit命令把container制作成一个image,但是这样次数多了image文件会越来越臃肿。所以我们使用Dockfiler。
Dockerfile:
**FROM:**我们要制作的image必然是基于现有的某个image的基础,from命令就是用来指定使用哪个基础的image的
COPY && ADD:copy命令是把宿主机上的文件拷贝到image中,add可以指定一个文件的URL,然后Docker先下载它再拷贝到image中。
COPY <src>...<dest>
这里表示目录或者文件src被复制并添加到容器的文件系统中的指定路径dest。
目标路径可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录使用WORKDIR来指定)
CMD:指定启动一个container之后,默认执行的命令,
RUN:指定了在构建image的时候要执行的命令,举个栗子:如果我们需要这个image里面有git,那么就在Dockerfile里面写:RUN apt-get -y install git
这里-y
表示对所有的询问选择是,不提示。
我们要尽量减少使用RUN命令,因为每执行一个指令都相当于让我们的image增加了一层只读层,所以可以使用下面的方法减少指令使用次数:
RUN apt-get update && \
apt-get -y install build-essential && \
apt-get -y install supervisor && \
ENV:设置环境变量,格式为env k v
EXPOSE:指定端口,使容器的应用可以通过端口和外部交互
**WORKDIR:**命令用于设置CMD知名的命令的运行目录
创建image:写好Dockerfile之后,在文件所有路径下:
docker build -t image-name .
发布image文件:
首先去Docker hub注册一个账号
先登录: docker login
然后为本地的image标注用户名和版本:docker image tag [imageName] [username]/[repository]:[tag]
然后发布image文件:docker image push [username]/[repository]:[tag]
Docker-compose详解
Docker compose是一个用来定义和运行复杂应用的Docker工具,一个应用如果需要使用Docker容器,通常由多个容器组成,使用Docker compose不在需要使用shell脚本来启动容器,compose通过一个配置文件来管理多个Docker容器,在配置文件中所有的容器都相当于services,然后使用Docker-compose脚本来start,stop和restart应用。所以这个工具对于需要组合使用多个容器来开发的应用来讲非常好。
安装Docker-compose:
sudo curl -L https://github.com/docker/compose/releases/download/1.16.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version
Dockerfile可以让用户管理一个单独的应用容器,Docker-compose却允许用户在一个YAML格式的配置文件中定义一组相关联的应用容器,这被称之为一个project,打比方说一个web服务器再加上后端的数据库container。
Docker-compose实战:
这里我们使用Docker-compose来搭建一个Django+PostgreSQL的开发环境。
定义项目组件:
- 新建一个项目目录:
mkdir django_test
- 然后在项目的目录下面创建一个名为Dockerfile的文件,然后添加内容:
FROM python:3
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
ADD requirements.txt /code/
RUN pip install -r requirements.txt
ADD . /code/
这里相当于创建了Django的运行环境
- 然后在当前项目目录下创建docker-compose.yml文件:
version: '3'
services:
db:
image: postgres
web:
build: .
command: python3 manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
depends_on:
- db
这里举个简单的例子:
version: '2'
services:
web:
build: . # web容器通过当前路径下的Dockerfile生成的
ports: # 容器内的5000端口映射到主机上的5000端口
- "5000:5000"
volumes: # 将当前目录挂载到容器内的/app
- .:/app
depends_on: # 这个web容器依赖与db容器
- db
db:
image: postgres:9.5
代表这个应用定义了两个服务即web和db
- 启动应用:
# docker-compose up
- 停止应用:
# docker-compose stop
- 查看信息:
# docker-compose ps