Docker入门
1、Docker概述
纯物理服务器部署
- 部署非常慢:购买服务器 --> 部署操作系统 --> 安装应用,这仅仅是对于一台服务器的流程。如果对于集群,有多台服务器,部署就会非常慢
- 成本非常高:服务器成本高
- 资源浪费:如果每台服务器的配置都比较高,但是仅仅运行一个应用程序。那就造成资源浪费
- 难于迁移和扩展:迁移时候,需要把服务器的所有配置流程重新造作一边。
- 可能会被限定硬件厂商:应用程序如果是运行在A操作系统,那怎么配置在具有B操作系统的服务器上
很多时候,我们只想要一个单独的执行环境,而不需要费劲虚拟出一个完整的计算机。比如仅仅希望同时使用MySQL5.7和5.8。
虚拟出一台计算机的成本,远高于只虚拟出一个隔离的程序运行环境。容器技术思想正是基于此。
举个例子
2、Docker基础组件
Docker的核心是运行镜像,生成对应的容器。
核心组件:
- image镜像,镜像是一个只读模板,用于构建容器,即我们将应用程序运行所需的环境,打包为镜像文件。也可以通过dockerfile文本描述镜像的内容。
- container容器,是镜像运行的实例,我们的应用程序就运行在容器中
- Registry镜像仓库,用于保存镜像文件,提供上传下载镜像文件,作用好比GitHub
- dockerfile,将所部署项目的操作,写成部署脚本dockerfile。且该脚本还能构建出镜像文件
3、Docker的基础命令
以nginx web为例子,如果是单台服务器上配置80端口的流程是:
1)开启服务器
2)在服务器上安装好运行nginx所需的依赖
3)安装nginx
4)修改nginx配置文件
5)启动nginx
6)客户端访问nginx
显然,如果是多台服务器,那要一一配置十分麻烦。而在Docker下,只需三个步骤
1)获取镜像
2)运行镜像,生成容器
3)客户端访问
具体流程是:
1)检索所需的镜像文件是否存在
docker search nginx
2)获取镜像:从配置好的Docker镜像站中,拉取nginx镜像
docker pull nginx
3)查看本地的Docker镜像有哪些
docker image ls
# 或者 docker images
4)运行该nginx镜像:运行出具体的容易,然后这个容器就跑着一个nginx服务
docker run -d -p 80:80 nginx
-d:后台运行容器
-p 80:80:端口映射,宿主机端口:容器内端口,即若访问宿主机的这个端口,也就访问到了容器内的端口
5)查看容器是否在线运行
6)服务端访问80端口
7)停止运行的容器
docker stop 容器ID/名字
4、Docker生命周期详解
5、docker镜像
5.1 利用docker使用不同的操作系统
我们一直以来使用VMware虚拟机安装的系统,是一个完整的系统文件,包括两部分
- linux内核,作用是提供操作系统的基本功能,以及和机器硬件交互
- Ubuntu / Centos等发行版,作用是提供软件功能,利用Ubuntu 的apt安装包管理,Centos的yum安装包管理
因此,一个完整的系统,是由linux的内核+发行版,才组成了一个可以使用的完整的系统。就好比基于安卓系统,小米、华为等在上面开发了自己的系统。
是否有一个办法,可以灵活的替换发行版,让我们使用不同的系统?
那么docker就实现了这个功能,技术手段就是docker images
利用docker容器,可以获取不同的发行版镜像,然后基于该镜像,运行出各种容器
具体操作流程:
1)利用docker获取不同的发行版镜像
docker pull ubuntu
docker pull centos
2)确认宿主机的发行版本
# Ubuntu命令
cat /etc/lsb-release
3)运行centos发行版,即运行容器,且进入容器内
docker run -it 5d0da3dc9764 bash
参数解释:
-i
交互式命令操作
-t
开启一个终端
5d0da3dc9764
是镜像的id
bash
进入容器后,执行的命令
3)查看容器内的发行版
# centos命令
cat /etc/redhat-release
4)退出
exit
5.2 docker镜像原理
docker镜像不包含linux内核,和宿主机共用。如果想要定义一个mysql 5.6镜像,我们会这么做
- 获取基础镜像,选择一个发行版平台 (ubutu,centos)
- 在centos镜像中安装mysql 5.6软件
- 导出镜像,可以命名为mysql 5.6镜像文件
从这个过程,我们可以感觉出这是一层一层的添加的,docker镜像的层级概念就出来了,底层是centos镜像,上层是mysql 镜像,centos镜像层属于父镜像。
Docker镜像是在基础镜像之后,然后安装软件,配置软件,添加新的层,构建出来。
这种现象在学习dockerfile构建时候,更为清晰。
# 进入容器内部
docker exec -it 容器id bash
Docker为什么分层镜像?
镜像分享一大好处就是共享资源,例如有多个镜像都来自于同一个base镜像,那么在docker host只需要存储一份base镜像。
内存里也只需要加载一份host,即可为多个容器服务
即使多个容器共享一个base镜像,某个容器修改了base镜像的内容,例如修改/etc/下配置文件,其他容器的/etc/下内容是不会被修改的,修改动作只限制在单个容器内,这就是容器的写入时复制特性 (Copy-on-write)
可写的容器层
当容器启动后,一个新的可写层被加载到镜像的顶部。这一层通常被称为容器层。容器层的下面都称为镜像层
所有对容器的修改动作,都只会发生在 容器层 里,只有 容器层 是可写的,其余镜像层 都是只读的。
只有当需要修改时才复制一份数据,这种特性被称作 Copy-on-Write。可见,容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改
这样就解释了我们前面提出的问题: 容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改所以镜像可以被多个容器共享
6、Docker镜像管理
6.1 获取镜像
1、查看docker镜像的存储路径
zxm@ubuntu:~$ docker info | grep Root
Docker Root Dir: /var/lib/docker
查看具体内容
ls /var/lib/docker/image/overlay2/imagedb/content/sha256 -l
2、使用不同的镜像,生成容器
docker run -it -rm centos bash
-it
开启一个交互式的终端
--rm
容器退出时删除该容器
6.2 查看镜像
# 查看所有镜像信息
docker images
# 仅查看ubuntu
docker images ubuntu
# 只列出id
docker images -q
# 格式化输出,输出id和Repository
docker images --format "{{.ID}}--{{.Repository}}"
# 以表格形式输出
docker images --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}"
# 查看镜像的详细信息
docker image inspect 镜像id(前三位即可)
# 在docker hub中搜索镜像
docker search 镜像名
# 查看容器内进程信息的命令
docker top 容器id
# 查看容器内资源
docker stats 容器id
# 查看容器的具体信息
docker inspece容器id
6.3 删除镜像
根据镜像的id、名字、摘要等删除。
docker rmi hello-world
需要注意的是,被删除的镜像,不得有依赖的容器记录
此时需要先删除对应的容器记录
docker rm cba633bf1589
再删除容器
6.4 导出导入镜像
# 导出并压缩镜像到/opt目录下
docker image save centos > /opt/centos.tgz
# 导入/opt目录下的镜像
docker image load -i /opt/centos.tgz
6.5 容器管理
docker run
等于创建+启动
docker run 镜像名
,如果镜像不存在本地,则会在线去下载该镜像
注意:
- 容器内的进程必须处于前台运行状态,否则容器就会直接退出。也就是如果自己部署一个容器运行,命令不得后台运行,需要前台运行。
- 如果容器内,什么事也没做,容器也会挂掉。也就是说,容器内必须有一个进程在前台运行。
具体命令:
1)docker run centos
这个写法,会产多多独立的容器记录,且容器内没有程序在跑,因此挂了。只会增加多条容器记录
2)运行容器,且进入容器内,且在容器内执行某个命令
3)开启一个容器,让它帮你运行某个程序,属于前台运行,会卡主一个终端
docker run centos ping baidu.com
4)运行一个活着的容器,docker ps可以看到的容器
-d
:让容器在后台跑着 (针对宿主机而言)
返回容器id
docker run -d centos ping baidu.com
还可以增加其他参数
docker run -d --rm --name pybaidu centos ping baidu.com
--rm
:容器挂掉之后,自动删除记录(删除的是docker ps -a 里面查看的记录)
--name
:给容器起个名字
5)查看容器日志,刷新日志
docker logs -f 容器id
docker logs 容器id | tail -5
6)进入到一个正在运行的容器空间内
docker exec -it 容器id bash
7)查看容器的详细信息,用于高级的调试
docker container inspect 容器id
8)容器的端口映射
后台运行nginx容器,且起个名字,且端口映射宿主机的85端口,访问到容器内的80端口
docker run -d --name zxm_nginx -p 85:80 nginx
查看容器的端口转发情况
docker port 容器id
9)容器的提交
运行基础的centos,在容器内安装vim,然后提交新的镜像。
新的镜像再运行出的容器,默认就携带vim了
docker run -it centos
# 进入centos后,安装vim
yum install vim
# 退出
exit
# 提交容器
docker commit 容器id 新的镜像名
7、Dockerfile
7.1 Dockerfile基础命令
镜像是多层存储,每一层在前一层的基础上进行修改;
容器也是多层存储,以镜像为基础层,在其基础上加一层作为容器运行时的存储层
创建镜像的两个方法
- 手动修改容器内容,然后
docker commit
提交容器为新的镜像 - 通过在
dockerfile
中定义一系列的命令和参数构成的脚本,然后这些命令应用于基础镜像,依次添加层最终生成一个新的镜像。极大的简化了部署工作。
dockerfile主要组成部分
-
基础镜像信息
FROM centos:6.8
-
制作镜像操作指令
RUN yum insatll openssh-server -y
-
容器启动时执行指令
CMD["/bin/bash"]
-
FROM 这个镜像的妈妈是谁?(指定基础镜像)
-
MAINTAINER 告诉别人,谁负责养它?(指定维护者信息,可以没有)
-
RUN 你想让它干啥 (在命令前面加上RUN即可)
-
ADD 添加宿主机的文件到容器内,还多了一个自动解压的功能
-
COPY 作用和ADD是一样的,都是拷贝宿主机的文件到容器内,COPY就是仅仅拷贝
-
WORKDIR 我是cd,今天刚化了妆 (设置当前工作目录)
-
VOLUME 给它一个存放行李的地方 (设置卷,挂载主机目录)
-
EXPOSE它要打开的门是啥(指定对外的端口),在容器内暴露一个端口 EXPORT 80
-
CMD 奔跑吧,兄弟! (指定容器启动后的要干的事情)
7.2 Dockerfile实践–重定向nginx
需求,通过Dockerfile,构建nginx镜像。运行容器后,生成的页面是“中华人民共和国是工人阶级领导的、以工农联盟为基础的人民民主专政的社会主义国家”
1、创建Dockerfile(文件名必须是这个)
mkdir docker-learn
vim Dockerfile
# 文件内写入以下内容
FROM nginx
RUN echo '<meta charset=utf8>中华人民共和国是工人阶级领导的、以工农联盟为基础的人民民主专政的社会主义国家.' > /usr/share/nginx/html/index.html
2、构建Dockerfile
docker build .
3、修改镜像名字
docker tag 2b7e8ce80df1 my-nginx
当然,也可以将构建的时候同时修改名字
docker build -t 'my-nginx' .
4、运行该镜像
docker run -d -p 80:80 my-nginx
5、客户端运行该端口
7.3 命令详解
7.3.1 COPY
1、COPY指令从宿主机复制文件/目录到新的一层镜像内
copy 宿主机文件目录 镜像内目录
2、支持多个文件,以及通配符形式复制,语法要满足Golang的filepath.Match
copy zxm* /tmp/cc?.txt. /home/
3、COPY指令能够保留源文件的元数据,如权限,访问时间等等,这点很重要
7.3.2 ADD
特性和COPY基本一致,不过多了些功能
1、源文件是一个URL,此时docker引擎会下载该链接、放入目标路径,且权限自动设为600,若这不是期望结果,还得增加一层RUN指令
2、源文件是一个URL,且是一个压缩包,不会自动解压,也得单独用RUN指令解压
3、源文件是一个压缩文件,且是gzip,bzip2,xz,tar情况,ADD指令会自动解压缩该文件到目标路径
7.3.3 CMD
用法,注意是双引号
CMD["参数1""参数2"]
在指定了entrypoint指令后,用CMD指定具体的参数
docker不是虚拟机,容器就是一个进程,既然是进程,那么程序在启动的时候需要指定些运行参数,这就是CMD指令作用
例如
1)centos镜像默认的CMD是["/bin/bash"]
,直接docker run -it centos
会直接进入bash解释器.
2)["cat","/etc/os-release"]
,等价于命令行的直接操作 docker run -t centos cat /etc/os-releasea
CMD运行she11命令,也会被转化为shel1形式
例如CMD echo $PATH
会被转化为CMD ["sh","-c","echo $PATH"]
CMD 用于容器内运行程序的坑
把宿主机安装,启动nginx的理念放入到dockerfile
1、RUN yum install nginx
2、RUN 配置文件修改 sed
# 这是错误的,容器是启动不了。因为容器内的程序必须是前台运行
3、RUN systemctl start nginx
这里要注意的是,docker不是虚拟机的概念,虚拟机里的程序运行,基本上都是在后台运行,利用systemctl
运行,但是容器内没有后台进程的概念,必须在前台运行。
容器就是为了主进程而存在的,主进程如果退出了,容器也就失去意义,自动退出。
例如刚才的问题
CMD systemctl start nginx
这样的写法是错误的,容器会立即退出。因为systemctlstart nginx
是希望以守护进程形式启动nginx,且CMD命令会转化为
CMD ["sh","-c","systemctl start nginx"]
这样的命令主进程是sh解释器,执行完毕后立即结束了,因此容器也就退出了。
因此正确的做法应该是
CMD ["nginx","-g","daemon off;"]
7.3.4 ENTRYPOINT
作用和CMD一样,都是在指定容器启动程序以及参数.
当指定了ENTRYPOINT之后,CMD指令的语义就有了变化,而是吧CMD的内容当作参数传递给ENTRYPOINT指令
1、准备一个Dockerfile
FROM ubuntu
RUN apt-get update && apt-get install -y curl
CMD ["curl", "-s", "http://ipinfo.io/ip"]
2、构建镜像
docker build .
3、检查镜像并修改名字
docker images
docker tag 93ef97d8f86f ubuntu-curl
4、运行镜像,生成容器记录,没有前台运行,因此立即挂了
docker run ubuntu-curl
5、上述运行正确,但是想再传入一个参数,该怎么办?
比如命令行输入curl -s http://ipinfo.io/ip -I
,获得如下结果
我想通过使用docker run ubuntu-curl -I
,但是报错。发现是无法直接传入参数的,因为该形式是覆盖镜像中的cmd。就好比把该docker镜像,当做一个环境,去执行后面的命令
6、想要正确的给容器传入一个 -I
参数该怎么办
方法1:docker run ubuntu-curl curl -s http://ipinfo.io/ip -I
,但是每次需要把cmd里完整的命令敲一遍。
方法2:修改Dockerfile,不用CMD,用ENTRYPOINT
FROM ubuntu
RUN apt-get update && apt-get install -y curl
ENTRYPOINT ["curl", "-s", "http://ipinfo.io/ip"]
然后重新构建
docker build .
docker tag 09af558344b2 ubuntu-curl-new
docker run ubuntu-curl-new -I
7.3.5 ENV
ENV NAME="zxm"
ENV AGE="18"
ENV MYSQL VERSION=5.6
后续所有的操作,通过$NAME
就可以直接获取变量值
ARG和ENV一样,用于设置环境变量
区别在于ENV 无论是在镜像构建时,还是容器运行,该变量都可以使用
ARG只是用于构建镜像需要设置的变量,容器运行时就消失了
7.3.6 VOLUME
容器在运行时,应该保证在存储层不写入任何数据,运行在容器内产生的数据,我们推荐是挂载,写入到宿主机上,进行维护。
VOLUME /data
将容器内的/data
文件夹 ,在容器运行时,该目录自动挂载为匿名卷,任何向该目录中写入数据的操作,都不会被容器记录,保证的容器存储层无状态理念
Dockerfile文件
FROM centos
VOLUME ["/data1","/data2"]
该容器运行时候,这2个目录自动和宿主机的目录做好映射关系
docker build .
docker inspect 5b12af9d63e9 # 查看详细信息
容器数据挂载的方式,除了通过dockerfile,指定VOLUME目录。
还可以通过dockerrun-v 参数
,直接设置需要映射挂载的目录
7.3.7 EXPOSE
指定容器运行时对外提供的端口服务,
帮助使用该镜像的人,快速理解该容器的一个端口业务
docker port #查看容器端口
docker run -p #宿主机端口: 容器端口
docker run -P # 作用是随机宿主机端口: 容器内端口
7.3.8 WORKDIR
用于在dockerfile中,目录的切换,更改工作目录
WORKDIR /opt
7.3.9 USER
用于改变环境,用于切换用户
USER root
USER zxm
推荐一个零声学院的C++服务器开发课程,个人觉得老师讲得不错,
分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,
fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
TCP/IP,协程,DPDK等技术内容
点击立即学习:C/C++后台高级服务器课程
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!