1. docker入门
1.1. 什么是docker docker是一个开源的应用容器引擎,你可以将其理解为一个轻量级的虚拟机,开发者可以打包他们的应用以及依赖包到一个可移植的容器中(可以理解为是一个另外的虚拟机,里面只装我们需要的软件,然后打包成一个容器)然后发布到任何流行的linux机器上。
1.2.为什么要使用Docker? 作为一种新型的虚拟化方式,docker跟传统的虚拟化方式相比具有众多的优势。
1.2.1 更有高效的的利用系统资源 由于容器不需要进行硬件虚拟及运行完整操作系统等额外开销,docker对系统资源的利用率更高。 无论是应用执行速度、内存损耗或则文件存储速度,都要比传统虚拟机技术更高效,因此,相比虚拟化技术,一个相同配置的主机,往往可以运行更多数量的应用。
1.2.2 更快速的启动时间 传统的虚拟机技术启动应用服务往往需要数分钟,而docker容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级,甚至毫秒级的启动时间,大大的结余额了开发、测试、部署的时间,(也就是我们把需要的容器时存放到容器中,而启动应用的消耗时间比传统的虚拟机还快)
1.2.3 一致的运行环境 开发过程中一个常见的问题时环境一致性问题,由于开发环境、测试环境、生成环境不一致,导致有些bug并未在开发过程中发现,而docker的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现【这段代码再我机器上运行没问题】这类问题(也就是,比如我们开发环境中代码已经部署完成,而要交给运维人员部署到正式环境上运行,为了减少时间,我们可以使用docker打包成一个镜像丢给运行人员,这样也保证了代码与环境的一致性,大大减少了部署时间)
1.2.4 持续交付和部署 对开发和运行人员来说,最希望的就是一次创建或配置,可以再人一地方正常运行(比如你需要把一套代码部署再多台服务器上运行,传统的做法就是,复制代码,放到每个服务器上并且还需要再新的服务器部署好环境,而使用docker,可以把所有操作写再一个dockerfile镜像文件中,只要把镜像文件集成为一个容器,就可以减少时间而快速的运行再每一台服务器上)
1.2.5 更轻松的迁移 由于docker确保了执行环境的一致性,使得应用的迁移更加容器,docker可以再很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的,因此用户可以很轻易的将再一个平台上运行的应用,迁移到另外一个平台上,而不用担心运行环境的变化导致应用无法正常的运行的情况(把再一台服务器上所需要的环境以及代码全部打包成一个进行,而后能随意部署迁移到任何一个服务器上或则云上,都可以正常使用,不会出现某些环境未安装或则不符合版本的一系列问题)
1.2.6 更轻松的维护和扩展 docker使用的分层存储以及镜像的技术,使得应用重复部分的服用更为容易,也使得应用的为何更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。(比如再一个dockerfile镜像文件中,还想追加一个扩展或则插件,可以使用命令再dockerfile文件中增加)
此外,docker团队同各个开源项目团队一起维护了大批高质量的官方镜像,既可以直接再生成环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。
1.4 docker的主要用途,目前有三大类
- 提供一次性的环境,比如,本地测试他人的软件,持续集成的时候提供单元测试和构建环境
- 提供弹性的云服务,因为docker容器可以随开随关,很适合动态扩容和缩容。
- 组件微服务架构,通过多个容器,一台机器可以跑多个服务,因此再本机就可以模拟除微服务架构(比如,需要负载均衡的搭建,传统方式是需要买多台服务器进行搭建,而docker只需要再一台服务器上创建多个容器即可)
扩容和缩容,对于我们的系统来说再项目运行过程中会存在这最高峰值,和最低峰值,整个项目运行过程中并不是一直时平稳的访问,对于这种时候如果说一次性就部署N个机器,但是实际上只有再某几个时候又高峰值其余时间没有就会显得比较浪费,这个时候如果说通过docker虚拟化多个机器,然后通过多docker进行控制启动与停止实现扩容和缩容(就是比如有一个活动,再每天10-12点之间有大量用户参与活动,这时候如果使用多台服务器的话是比较合理的,能挡住高峰,而活动过后,有些服务器没有用到过而会显得比较浪费,也不能做任何操作,而docker再不需要使用的时候可以把docker停止,这就是缩容,而需要它的时候就把它开启,这就是扩容,这样也不会占用资源)
- 加速本地开发,通过docker能够快速搭建好开发和运行环境,并且该环境可以直接传递(传统虚拟机部署环境需要1个钟左右才能部署完毕,而使用docker容器部署消耗时间比虚拟机还要低,部署完后还可以迁移到任何机器上)
- 给测试和产品部署(也可以给测试人员专门部署测试)
- 自动打包和部署应用。
- 创建清凉、私有的paas环境
- 自动化测试和持续集成、部署。
- 部署并扩展Web应用、数据库和后端服务器。(一件部署,把需要安装的环境全部写在dockerfile镜像文件中部署)
- 创建安全沙盒
2. centos安装docker
更新yum update 到最新的版本
yum update
如果有老版本docker的话,需要进行卸载
yum remove docker docker-common docker-selinux docker-engine
安装docker需要的软件包(依赖包)
yum install -y yum-utils device-mapper-persistent-data lvm2
设置yum源
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
查看docker版本
yum list docker-ce --showduplicates|sort -r
安装docker
yum install docker-ce-18.03.1.ce -y
启动docker
systemctl start docker
加入开机自启
systemctl enable docker
配置国内镜像
vi /etc/docker/daemon.json
{ "registry-mirrors": ["https://cr.console.aliyun.com/"] }
# 查看docker启动状态
ps -aux | grep docker
2.1 如上面无法配置国内镜像,保存daemon.json文件失败
原因分析:一般都是因为一次创建了文件夹同时创建了文件导致,vi /etc/docker/demo.json
解决方案:
手动 先进入etc目录下:cd /etc/
手动创建文件夹docker:mkdir docker/
进入docker:cd docker/
创建demo.json文件并进入编辑:vi demo.json
按i进入编辑模式
编辑完后,按ESC退出编辑模式,然后保存并退出: :wq
此时就可以了。
2.2 装成功后
使用命令行 :docker 出现docker的一些命令则证明安装成功
4. docker基本概念
docker包括三个基本概念:镜像、容器、仓库
这三部分组成了docker的整个生命周期,容器是由镜像实例化而来的(例如composer,composer.json文件中,都是一些我们需要安装的插件,而composer update 更新下来后,我们就可以使用这些插件里面的功能,也就是说,容器就是功能,而composer是代码)这和我们学习面向对象的概念十分相似,我们可以把镜像想象成类,把容器想像成类经过实例化后的对象,这样就非常好理解镜像和容器的关系了(就是一个类被new出来后可以直接使用了)
4.1 镜像(image) docker的镜像概念类似于虚拟机里的镜像,是一个只读的模板,一个独立的文件系统,包括运行容器所需要的数据,可以用来创建新的容器(镜像只是一个文件,来描述一个容器所需要的功能或则插件软件)
例如:一个镜像可以包含一个完整的ubuntu操作系统环境,里面仅安装了MySQL或用户需要的其他应用程序(例如:一个类里面只是写了用户登陆以及注册)
docker的镜像实际上由一层 的文件系统组成的,这种层级的文件系统
镜像可以基于dockerfile构建,dockerfile是一个描述文件,里面包含若干条命令,每条命令都会对基础文件系统创建新的层次结构(dockerfile只是一个命令文件,里面包含了所需要安装的操作软件的安装命令)
docker提供了一个很简单的机制来创建镜像或则更新现有的镜像,用户甚至可以直接从其他人那里下载一个已经做好的镜像来直接使用。
4.2 容器(Container) docker利用容器来运行应用 docker容器时由docker镜像创建的运行实例,docker容器类似虚拟机,可以直接的操作包括启动、停止、删除等,每个容器间时相互隔离的,容器中会运行特定的应用,包含特定应用的代码及所需的依赖文件(容器其实是镜像实例出来的,容器里面包括镜像dockerfile文件所需要安装的应用程序)
可以把容器看作是一个简易版的linux环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其他的应用程序。
4.3 仓库(Reoisutory) 如果你使用过git和github就很容易理解docker的仓库概念,docker仓库的概念跟git类似,注册服务器可以理解为github这样的托管服务(其实就是把我们创建好的镜像存放到仓库中)
docker仓库是用来包含镜像的位置,docker提供一个注册服务器来保存多个仓库,每个仓库又可以包含多个具备不同tag的镜像。
仓库支持的操作类似git,当用户创建了自己的镜像之后就可以使用push命令将它上传到共有或则私有仓库,这样下次再另外一个机器上使用这个镜像时候,只需要从仓库上pull下来就可以(可以把我们创建好的镜像上传到私有云或则公有云上,需要使用直接pull下来)
- 镜像结构 镜像的最底层必须是一个称为启动文件系统的镜像,用户不会再这一层直接打交道,bootfs的上层镜像叫做根镜像(rootfs)它在通常情况下是一个操作系统,如ubuntu、debian和centos等,用户的镜像必须构建于根镜像址上。
查看镜像命令
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZ
参数介绍:
REPOSITORY:仓库名称,仓库一般用来存放统一类型的镜像,其名称由它的创建者指定,如果创建时没有指定则为。仓库的名称有下面几种形式。
[namespace\centos]:由命名空间和实际的仓库名称组成,中间通过\隔开,当你在docker
hub注册一个账号时,账号名便自动称为了你的命名空间,该命名空间时用来区分docker hub
上注册的不同用户或则组织,如果你像创建一个分发到dockerhub上去的镜像,必须指定命名空间,如果不指定或则指定了但命名空间不服务,将会报错(docker hub 上的命名空间,必须根你镜像的仓库名称对应)
[centos]:只有仓库名,对于这种没有命名空间的仓库名,我们可以认为它属于顶级命名空间,该空间的仓库只用于官方的镜像,由docker官方进行管理,但一般会授权给第三方进行开发维护,用户在本地创建的镜像也可以这样命名,但是无法分发到dockerHub上进行共享。(如果没有指定命名空间的话,无法进行上传到docker Hub上)
TAG:用于区分统一仓库中的不同镜像,如果未指定,,默认为latest
IMAGE ID:每个镜像都由一个字符类型,长为64为的HashID,用来全网标识一个镜像。
CREATE:镜像的创建时间
VIRTUAL SIZE:镜像所占用的虚拟大小,该大小包含了所有共享文件的大小。
下面通过运行如下命令下载docker镜像
docker run 镜像 - 运行镜像打包成容器命令(实例化)
下面就是安装ubuntu镜像并输出hello world docker文字描述
[root@localhost ~]# docker run ubuntu echo "hello world docker"
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
d51af753c3d3: Pull complete
fc878cd0a91c: Pull complete
6154df8ff988: Pull complete
fee5db0ff82f: Pull complete
Digest: sha256:747d2dbbaaee995098c9792d99bd333c6783ce56150d1b11e333bbceed5c54d7
Status: Downloaded newer image for ubuntu:latest
hello world docker
如上命令使用docker run 命令运行一个镜像时,docker首先是会在本机寻找该镜像,如果本机不存在,会在docker hub
上面搜索符合条件的镜像并将其下载下来运行
dockerhub : https://hub.docker.com docker hub
当然也可以通过pull 命令来完成拉去镜像(从 docker hub 上拉去)
如果出现下面错误,则需要登陆docker hub
Error response from daemon: pull access denied for ngnix, repository does not exist or may require 'docker login'
首先需要到 https://hub.docker.com 网址上注册一个账号
然后使用该命令
[root@localhost ~]# docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: ajoni
Password:
进行登陆
在执行docker pull nginx 就可以了
然后再查看:
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 1d622ef86b13 2 weeks ago 73.9MB
nginx latest 602e111c06b6 2 weeks ago 127MB
删除镜像
-- 指定删除
docker rmi 镜像id(image id)
-- 强制删除
docker rmi -f 镜像id(image id)
-- 删除所有容器
docker rmi $(docker images -q)
- dockerfile 介绍及构建镜像 利用docker快速安装一个redis镜像,了解dockerfile指令 dockerfile是一个文本文件,其内容包含了一条条指令,每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建(就是dockerfile文件中,每一条命令都是安装的操作)
这种方式是比较流行的方式,就是将需要对镜像的操作全部写到一个文件中,然后使用docker
build命令从这个文件中创建镜像,这种方法可以使镜像的创建变得透明化和独立化,并且创建过程可以被重复执行,dockerfile文件以执行为单位,dockerfile命令。(把所需要按爪给你的所有操作命名存放到dockerfile文件中,docker
build 命名就是把这个镜像实例化为一个容器才可使用,相当于把一个类,new成一个对象才可以调用)
6.1 dockerfile 指令
6.1.1 from指定基础镜像 指定待扩展的父级镜像,除了注释外,再我呢见开头必须是一个from指令,接下来指令便再这个父级镜像中的环境中运行,知道遇到下一个from指令。通过添加多个from命令可以再同一个dockerfile文件中创建多个镜像(意思就是再dockerfile文件中命名这个操作软件是安装再这个系统中)
所谓定制镜像,那一定是以一个镜像为基础,再其上进行定制,就像我们之前运行一个redis镜像的容器,再进行修改一样,基础镜像是必须指定的,而from就是指定基础镜像,因此一个dockerfile中from是必备的指令,并且必须是第一条指令(from说明是我们dockerfile所安装的应用是运行再from基础镜像中)
再docker store
上有非常多的高质量的官方镜像,有可以直接拿来使用的服务类的镜像,如nginx、redis、mongo、MySQL、httpd、php、tomcat等,如果没有找到对应服务的镜像,官方镜像中海提供了一些更为基础的操作系统镜像,如ubuntu、debian、centos、alpine等这些操作系统的软件库
一般会以alpine为主,因为节约的资源比较少
6.2 Run执行命令 RUN 指令是用来执行命令行命令的
格式:
RUN \<command\> (类似/bin/sh -cshell格式)
RUN ["executable","param1","param2"](exec格式)
类似shell脚本的风格:
FROM alpine
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
RUN apk add gcc g++ libc-dev wget vim openssl-dev make linux-headers
RUN mkdir -p /usr/src/redis
RUN cd /usr/src/redis
RUN wget -O redis-4.0.11.tar.gz "http://download.redis.io/releases/redis-4.0.11.tar.gz"
RUN tar -xzf redis-4.0.11.tar.gz -C /usr/src/redis
RUN cd /usr/src/redis/redis-4.0.11 && make && make PREFIX=/usr/local/redis install
6.2.1 MAINTAINER: 用来生命创建的镜像的作者西信息,再上述代码中,xxh是用户名,xxh@qq.co是邮箱,这个命令并不是必须的。
6.2.2 EXPOSE 用来指明容器内进程对外开放的端口,多个端口之间使用空替隔离,运行容器通过参数-p(大写)即可将EXPOSE里所指定的端口映射到主机上另外的随机端口,容器或主机就可以通过映射后的端口与此容器同心,同时,我们也可以通过-p(小写)参数将dockerfile中EXPOSE中没有列出的端口设置公开的(设置端口,其实就是为了两个不再同个容器中的容器,将此两个容器关联起来通讯)
6.2.3 ADD 向新镜像中添加文件,这个文件可以是一个主机文件,也可以是网络文件,也可以是一个文件夹
6.2.4 ENV 设置容器运行的环境变量,再运行容器的时候,通过-e参数可以修改这个环境变量值,也可以添加新的环境变量
注:dockerfile中每一个指令都会简历一层,RUN也不例外,每一个RUN的行为,就和刚才我们手工简历镜像过程一样,新建立一层,在其上执行这些命令,执行结束后,commit这一层的修改,构成新的镜像,使用dockerfile定制镜像而上面的这种写法,创建了很多层镜像,这是完全没有意义的,而且很多运行时不需要的东西,都被装进了镜像里,必须编译环境、更新软件包等等,结果就是产生非常臃肿、非常多层的镜像,不仅仅增加了构建部署的时间,也很容易出错,Union
FS 时有最大层的数限制的,比如AUFS曾经最大不得超过42层,现在不得超过127层。
6.3 dockerfile构建redis镜像 创建一个dockerfile的文件,注意没有后缀
(文件名也可以不叫dockerfile,但是docker默认找的就是这个文件,如果不是则需要自己指定)
下面我们使用dockerfile构建一个redis5镜像 再随意目录中,
创建一个Dockerfile文件,把下面代码复制进去
指定基础镜像
FROM centos
RUN groupadd -r redis && useradd -r -g redis redis
RUN yum update -y && yum install epel-release -y
RUN yum install wget -y && yum -y install gcc automake autoconf libtool make
RUN yum install gcc gcc-c++ -y
RUN mkdir -p /usr/src/redis
RUN wget https://github.com/antirez/redis/archive/5.0.7.tar.gz
RUN tar -zxvf 5.0.7.tar.gz -C /usr/src/redis
RUN cd /usr/src/redis/redis-5.0.7 && make && make PREFIX=/usr/local/redis install
再使用下面命令构建成一个镜像(注意后面还有一个点)
docker build -t redis5 .
根据上面的运行结果我们可以看到再执行一行Run之后就会出现一个 —>Running in
xxx的信息,对于dockerfile的执行来说它会没执行一行命令就会创建一个临时镜像,然后下面的命令就会基于这个镜像继续构建,构建完成就删除前面的镜像,直到最后异步生成我们的目标镜像
6.4 命令执行注意 再docker中的设计时采用文件系统,而再dockerfile中一个RUN代表一层,曾经最大不得超过42层,现在时不得超过127层,而且再docker中下载的文件时会占用一定的资源。对于容器我们是尽量占用足够小的资源所以下载安装之后就要删除文件,对于命令之间我们通常是建议一些能一起执行的命令放在一起执行可通过
;\ 分割对于上面的错误主要包含有
- 下载安装的文件没有删除
- RUN层次太多
所以正确的写法应该如下
FROM centos
RUN groupadd -r redis && useradd -r -g redis redis
RUN yum update -y ; \
yum -y install gcc automake autoconf libtool make wget epel-release gcc-c++;
RUN mkdir -p /usr/src/redis; \
wget https://github.com/antirez/redis/archive/5.0.7.tar.gz; \
tar -zxvf 5.0.7.tar.gz -C /usr/src/redis; \
rm -rf 5.0.7.tar.gz; \
cd /usr/src/redis/redis-5.0.7 && make && make PREFIX=/usr/local/redis install;
命令 docker build -t 自定义仓库名 . 将dockerfile生成一个镜像
-t :指定要创建的目标镜像名
. 没有自定义dockerfile文件名,则需要手动指定文件。否则 .默认是指定dockerfile文件
8. 容器
8.1 基础操作
我们可以基于镜像构建成容器
命令
docker run -itd --name 容器名称(自定义)镜像名称:标识
docker run [OPTIONS] IMAGE [COMMAND] [ARG...
OPTIONS说明:
-a stain:指定标准输入输出呢日哦给你类型,可选 STDIN/STDOUT/STDERR 三项:
-d : 后台运行容器,并返回容器id
-i:以交互模式运行容器,通常与 -t同时使用;
–name=“nginx-lb”:为容器指定一个名称
–dns:0.0.0.0 指定容器使用的DNS服务器,默认是宿主一致。
-h :指定容器的hostname
-e:username="":设置环境变量
-env-file=[] 从指定文件读入环境变量
-cpusert="" or --cpuset=“0,1,2”:绑定容器到指定CPU运行
-m:设置容器使用内存最大值
–net="" 指定容器的网络链接类型,支持 bridge/host.none/container:四种类型
–link=[] 添加链接到另一个容器
–expose=[]; 开放一个端口或一组端口
将镜像实例化为容器
[root@localhost file]# docker run -itd --name redis50 redis5
ad372a46d0cad20ab3c96f5d91c1c268536a535bb8e8a7e7db9af04f504302e7
容器类型:
交互行容器,运行再前台,通常会指定有交互的控制台,可以给容器输入,也可以得到控制器的输出,创建日期的终端被关闭,再容器内部使用exit命令或则调用docker
stop、docker kill 命令后,容器会停止
后台行容器,运行再后台,创建启动之后就与终端无关,即便终端关闭了,改后台容器也依然存在,只有执行docker
stop或则dockerkill命令时候才能够使容器变成停止状态我们可以进入容器中的系统(其实容器就是一个终端,我们可以进入) docker exec -it redis50 bash
[root@ad372a46d0ca /]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
28: eth0@if29: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
如上命令我们就相当于进入容器中的系统了,同时我们也可以启动容器中的redis 我们可以查看容器中的进程,通过如下命令:
[root@localhost file]# docker top redis50
UID PID PPID C STIME TTY TIME CMD
root 19350 19336 0 17:28 pts/0 00:00:00 /bin/bash
root 31679 19336 0 17:35 pts/1 00:00:00 bash
下面就是进入容器中启动redis5
查看镜像的历史
docker history 镜像