Docker
Docker
什么是Docker
Docker 使用 Google 公司推出的 Go 语言 进行开发实现。
Docker 是linux容器的一种封装,提供简单易用的容器使用接口。它是最流行的Linux容器解决方案。
Docker 将应用程序与程序的依赖,打包在一个文件里面。运行这个文件就会生成一个虚拟容器。
Docker 的接口相当简单,用户可以方便的创建、销毁容器。
使用场景
- 在服务型环境中部署和调整数据库或其他应用
- 自动化测试和持续集成、发布
- 在服务型环境中部署和调整数据库或其他应用
为什么用docker
Linux容器
Linux容器(LXC)不是模拟一个完整的操作系统,而是对进程进行隔离。在正常进程的外面套了一个保护层,对于容器里面进程来说,它接触的资源都是虚拟的,从而实现和底层系统的隔离。
- 启动快
- 容器里面的应用,直接就是底层系统的一个进程,而不是虚拟机内部的进程。所以,启动容器相当于启动本机的一个进程,而不是启动一个操作系统,速度就快很多。
- 资源占用少
- 容器只占用需要的资源,不占用那些没有用到的资源;虚拟机由于是完整的操作系统,不可避免要占用所有资源。另外,多个容器可以共享资源,虚拟机都是独享资源。
- 体积小
- 容器只要包含用到的组件即可,而虚拟机是整个操作系统的打包,所以容器文件比虚拟机文件要小很多。
docker容器的优势
- 更高效的利用系统资源
- 由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker 对系统 资源的利用率更高。
- 更快速的启动时间
- 秒级启动,不需要部署系统,直接运行于宿主机内核
- 一致的运行环境
- 提供了除内核外完整的运行环境,确保应用运行环境一致。解决"这段代码在我机器运行没问题啊"之类的问题
- 持续交付和部署
- 更轻松的迁移
物理机,虚拟机,容器。
物理机,实实在在存在的计算机。
虚拟机,在软件层面上通过模拟硬件的输入和输出,让虚拟机的操作系统得以运行在没有物理硬件的环境中。
容器,与物理机共享核心
核心 Namespaces、CGroups、UnionFS,(命名空间、控制分组、镜像)
Namespaces,隔离命名空间
CGroups,隔离硬件资源
UnionFS,保存镜像
docker三大概念
镜像/image
docker镜像
- docker镜像就是一个只读的模板
- 镜像可以用来创建Docker容器。
- Docker提供了一个很简单的机制来创建镜像或者更新现有的镜像,用户甚至可以直接从其他人那里下载一个已经做好的镜像来直接使用。
image分层存储
因为镜像包含完整的root文件系统,体积是非常庞大的,因此docker在设计时按照Union FS的技术,将其设计为分层存储的架构。
镜像不是ISO那种完整的打包文件,镜像只是一个虚拟的概念,他不是一个完整的文件,而是由一组文件组成,或者多组文件系统联合组成。
容器/container
image和container的关系,就像面向对象程序设计中的 类和实例一样,镜像是静态的定义(class),容器是镜像运行时的实体(object)。
容器是从镜像创建的运行实例。它可以被启动、开始、停止、删除。每个容器都是相互隔离的,保证安全的平台。
可以把容器看做是一个简易版的Linux环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
注意:镜像是只读的,容器在启动的时候创建一层可写层作为最上层。
仓库/repository
仓库是集中存放镜像文件的场所。有时候把仓库和仓库注册服务器(Registry)混为一谈,并不严格区分。实际上,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。
仓库分为公开仓库(Public)和私有仓库(Private)两种形式。
最大的公开仓库是Docker Hub,存放了数量庞大的镜像供用户下载。国内的公开仓库包括Docker Pool等,可以提供大陆用户更稳定快读的访问。
当用户创建了自己的镜像之后就可以使用push命令将它上传到公有或者私有仓库,这样下载在另外一台机器上使用这个镜像时候,只需需要从仓库上pull下来就可以了。
注意:Docker仓库的概念跟Git类似,注册服务器可以理解为GitHub这样的托管服务。
docker Registry
Docker Registry 公开服务是开放给用户使用、允许用户管理镜像的 Registry 服 务。一般这类公开服务允许用户免费上传、下载公开的镜像,并可能提供收费服务 供用户管理私有镜像。
最常使用的 Registry 公开服务是官方的 Docker Hub,这也是默认的 Registry,并 拥有大量的高质量的官方镜像。
除此以外,还有 CoreOS 的 Quay.io,CoreOS 相 关的镜像存储在这里;Google 的 Google Container Registry,Kubernetes 的镜像 使用的就是这个服务
镜像加速器
国内的一些云服务商提供了针 对 Docker Hub 的镜像服务(Registry Mirror),这些镜像服务被称为加速器。常见 的有 阿里云加速器、DaoCloud 加速器、灵雀云加速器等。
使用加速器会直接从国内的地址下载 Docker Hub 的镜像,比直接从官方网站下载速度会提高很多。
centos安装docker
-
卸载旧版本
-
sudo yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-selinux \ docker-engine-selinux \ docker-engine
-
-
设置存储库
-
sudo yum install -y yum-utils \ device-mapper-persistent-data \ lvm2
-
sudo yum-config-manager \ --add-repo \ https://download.docker.com/linux/centos/docker-ce.repo
-
-
安装docker社区版
-
sudo yum install docker-ce docker-ce-cli containerd.io -y
-
-
修改一个配置文件(如果无法运行)
- cat /etc/docker/daemon.json
- 去掉{}里面的逗号就行
{"registry-mirrors": ["http://f1361db2.m.daocloud.io"]}
-
启动docker
- systemctl start docker
配置docker的镜像加速器
一条命令加速
curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://95822026.m.daocloud.io
加速器修改的其实是这个文件 /etc/docker/daemon.json
docker命令
增
- docker pull hello-world # 下载镜像
- docker run hello-world # 运行镜像,产生容器实例
- docker run 运行一个镜像,如果这个镜像不存在,自动也会下载
- docker run 镜像id前三位 # 也可以运行镜像
- docker save centos > /opt/centos.tar.gz #导出系统当前docker镜像
- docker load < /opt/centos.tar.gz #导入一个docker镜像
- docker run -it centos /bin/bash #运行centos进行,且以交互式形式,进入centos容器当中
- -i 交互式操作
- -t 开启一个终端提供访问
- centos 镜像名
- /bin/bash 指定容器运行shell解释器
- docker run -d centos /bin/sh -c "while true;do echo 好嗨哦; sleep 1;done"
- -d 后台运行
- -c "while true;do echo 好嗨哦; sleep 1;done" #后台运行一个shell脚本
删
-
docker rm 容器id # 删除容器
-
docker rmi 镜像id # 删除镜像, remove image
- 删除镜像前,需要确保这个镜像,没有依赖的容器记录
- docker rmi -f 镜像id # 强制删除镜像,跳过容器记录
-
docker rm `docker ps -aq` #一次性删除所有容器记录 #慎用!! -q 只展示数字ids
-
docker rmi `docker images -aq` #一次性删除所有镜像记录 #慎用!!!
改
查
- docker images # 查看当前机器上的镜像
- docker image ls # 同上
- docker container ls #查看正在运行的容器记录
-
容器运行的要点: docker容器 必须有后台进程在运行,否则容器就挂掉
-
- docker ps -a #所有运行过的容器记录
- docker container ls -a #与这个命令一样
- docker search hello-world #查询docker镜像,默认去docker hub搜索镜像
- docker logs -f 容器id #实时打印容器内的日志
- docker stop 容器id #停止正在运行的容器,会有一定的缓冲时间
- docker kill 容器id # 直接结束正在运行的容器
- docker start 容器id
提交创建自定义的镜像
-
运行一个centos容器记录,此时没有vim工具
- docker run -it centos /bin/bash
- yum install vim -y
- exit
-
退出容器,提交这个容器记录,创建新的image
- docker commit 容器id whj233/centos-vim
-
检查容器镜像
- docker images
-
.提交这个镜像到docker hub
- 需要保证image的tag是账户名,如果镜像名字不对,需要改一下tag
- 语法是: docker tag 仓库名 whj233/仓库名
- doccker tag whj233/centos-vim whj233/centos-vim
- 登录docker hub
- docker login
- 登录后,推送这个镜像,到docker hub
- docker push whj233/centos-vim
- 推送到docker hub公网后,就可以提供公网镜像下载了
- docker rmi -f centos-vim #删除本地镜像
- docker pull whj233/centos-vim
- 需要保证image的tag是账户名,如果镜像名字不对,需要改一下tag
容器端口映射
1.通过一条命令,运行一个python web容器
docker run -d -P training/webapp python app.py
-d 后台运行参数
-P 随机端口映射, # 宿主机的一个随机端口:映射到容器内暴露的端口 (8000)
training/webapp #运行的镜像名
python app.py #运行容器内的一个app.py脚本文件
利用dockerfile定制镜像
镜像是容器的基础,每次执行docker run的时候都会指定哪个镜像作为容器运行的基础。我们之前的例子都是使用来自docker hub的镜像,直接使用这些镜像只能满足一定的需求,当镜像无法满足我们的需求时,就得自定制这些镜像。
镜像的定制就是定制每一层所添加的配置、文件。如果可以吧每一层修改、安装、构建、操作的命令都写入到一个脚本,用脚本来构建、定制镜像,这个脚本就是dockerfile。
Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令 构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
FROM指令就是 指定哪一个系统,为基础镜像
FROM scratch #制作base image 基础镜像,尽量使用官方的image作为base image
FROM centos #使用base image
FROM ubuntu:14.04 #带有tag的base image
LABEL version=“1.0” #容器元信息,帮助信息,Metadata,类似于代码注释
LABEL maintainer=“whj233" #作者
#对于复杂的RUN命令,避免无用的分层,多条命令用反斜线换行,合成一条命令!
RUN yum update && yum install -y vim \
Python-dev #反斜线换行
RUN /bin/bash -c "source $HOME/.bashrc;echo $HOME”
WORKDIR /root #相当于linux的cd命令,改变目录,尽量使用绝对路径!!!不要用RUN cd
WORKDIR /test #如果没有就自动创建
WORKDIR demo #再进入demo文件夹
RUN pwd #打印结果应该是/test/demo
ADD and COPY
ADD hello / #把本地文件添加到镜像中,吧本地的hello可执行文件拷贝到镜像的/目录
ADD test.tar.gz / #添加到根目录并解压
WORKDIR /root
ADD hello test/ #进入/root/ 添加hello可执行命令到test目录下,也就是/root/test/hello 一个绝对路径
COPY hello test/ #等同于上述ADD效果
ADD与COPY
- 优先使用COPY命令
-ADD除了COPY功能还有解压功能
添加远程文件/目录使用curl或wget
ENV #环境变量,尽可能使用ENV增加可维护性
ENV MYSQL_VERSION 5.6 #设置一个mysql常量
RUN yum install -y mysql-server=“${MYSQL_VERSION}”
VOLUME and EXPOSE
存储和网络
EXPOSE 8080 #dockerfile的 expose参数,暴露容器的8080端口,提供给外部机器访问
RUN and CMD and ENTRYPOINT
RUN:执行命令并创建新的Image Layer
CMD:设置容器启动后默认执行的命令和参数
ENTRYPOINT:设置容器启动时运行的命令
Shell格式和Exec格式
RUN yum install -y vim
CMD echo ”hello docker”
ENTRYPOINT echo “hello docker”
Exec格式
RUN [“apt-get”,”install”,”-y”,”vim”]
CMD [“/bin/echo”,”hello docker”]
ENTRYPOINT [“/bin/echo”,”hello docker”]
通过shell格式去运行命令,会读取$name指令,而exec格式是仅仅的执行一个命令,而不是shell指令
cat Dockerfile
FROM centos
ENV name Docker
ENTRYPOINT [“/bin/echo”,”hello $name”]#这个仅仅是执行echo命令,读取不了shell变量
ENTRYPOINT [“/bin/bash”,”-c”,”echo hello $name"]
CMD
容器启动时默认执行的命令
如果docker run指定了其他命令(docker run -it [image] /bin/bash ),CMD命令被忽略
如果定义多个CMD,只有最后一个执行
ENTRYPOINT
让容器以应用程序或服务形式运行
不会被忽略,一定会执行
最佳实践:写一个shell脚本作为entrypoint
COPY docker-entrypoint.sh /usr/local/bin
ENTRYPOINT [“docker-entrypoint.sh]
EXPOSE 27017
CMD [“mongod”]
[root@master home]# more Dockerfile
FROm centos
ENV name Docker
#CMD ["/bin/bash","-c","echo hello $name"]
ENTRYPOINT ["/bin/bash","-c","echo hello $name”]
打包flask程序与dockerfile
构建一个dockerfile 与flask web应用,且外部客户端可以访问
-
创建一个flask 代码文件
-
[root@vultr ~]# vim flask.py #coding:utf8 from flask import Flask app=Flask(__name__) @app.route('/') def hello(): return "<h1>哈哈哈 flask</h1>" if __name__=="__main__": app.run(host='0.0.0.0',port=8080)
-
-
创建dockerfile,内容如下
-
确保和flask.py 在同一目录下
-
[root@vultr ~]# vim /opt/mydocker/Dockerfile FROM centos RUN yum install python-setuptools -y RUN easy_install flask COPY flask.py /opt/ WORKDIR /opt EXPOSE 8080 CMD ["python","flask.py"]
-
-
构建镜像image
- docker build -t whj233/flask-docker-hello .
- -t 指定镜像的版本名
- . 找到当前路径的 Dockerfile
- docker build -t whj233/flask-docker-hello .
-
查看创建好的images
- docker images
-
启动此flask-hello-docker容器,映射一个端口供外部访问
- docker run -d -p 8080:8080 whj233/flask-docker-hello
- -d 后台运行
- -p 指定端口映射 宿主机的8888映射到容器的8080
- whj233/flask-hello-docker 镜像名
- docker run -d -p 8080:8080 whj233/flask-docker-hello
-
查看容器的端口转发情况
- docker port 容器id
docker私有仓库的搭建
官方教程 https://yeasy.gitbooks.io/docker_practice/repository/registry.html
-
下载registry镜像并且启动私有仓库容器
-
docker run -d -p 5000:5000 --restart=always --name registry registry
-
这将使用官方的
registry
镜像来启动私有仓库。默认情况下,仓库会被创建在容器的/var/lib/registry
目录下。你可以通过-v
参数来将镜像文件存放在本地的指定路径。例如下面的例子将上传的镜像放到本地的/opt/data/registry
目录。 -
$ docker run -d \ -p 5000:5000 \ -v /opt/data/registry:/var/lib/registry \ registry
- -v 数据卷挂载,目录映射
- -v /opt/data/registry:/var/lib/registr
- -p 5000:5000
-
-
修改docker的配置文件,支持http方式的推送
-
vim /etc/docker/daemon.json
-
修改如下参数 {"registry-mirrors": ["http://f1361db2.m.daocloud.io"], "insecure-registries":["192.168.15.71:5000"] }
-
修改docker的启动服务命令,支持读取这个/etc/docker/deamon.json文件
- vim /lib/systemd/system/docker.service
- EnvironmentFile=-/etc/docker/daemon.json # 在[Service]加入
-
重新读取docker 配置文件
- systemctl daemon-reload
-
-
重启dockfer服务
- systemctl restart docker
-
重启了docker,刚才的registry容器进程挂掉了,因此重新启动它
- docker run --privileged=true -d -p 5000:5000 -v /opt/data/registry:/var/lib/registry registry
- --privileged=true docker容器的安全机制:设置特权级运行的容器
-
推送本地镜像到私有仓库中
- 修改本地镜像的tag标记号,指定私有仓库的地址传输
- docker tag docker.io/hello-world 192.168.86.128:5000/old-docker
- 推送到私有仓库
- docker push 192.168.86.128:5000/old-docker
- 修改本地镜像的tag标记号,指定私有仓库的地址传输
-
通过私有仓库的api,检查镜像数据
-
此时可以通过 私有仓库下载
- docker pull 192.168.86.128:5000/old-docker