Docker教程

部分内容来自狂神的视频

安装

Centos 7之后可以直接通过yum命令安装,先查看系统是否安装docker:

yum list installed | grep docker

没有安装就运行yum install docker -y,安装成功后使用docker --version查看版本。

卸载:

yum remove docker -y

安装成功后,可以通过systemctl start docker开启docker,然后运行一下hello world查看是否可以正常运行:

但是1.13的版本太老了,已经是17年的了,所以还得卸了,现在是分为CE版本和EE(收费)版本的。

首先安装一些必要的系统工具:

yum install -y yum-utils device-mapper-persistent-data lvm2

然后添加软件源信息,这里用阿里云的镜像:

yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

然后安装最新稳定版本:

yum -y install docker-ce

启动方式还是一样systemctl start docker:

然后改成国内源,不然后面拉镜像很慢甚至可能timeout,vim /etc/docker/daemon.json

{
 "registry-mirrors":["https://6kx4zyno.mirror.aliyuncs.com"]
}

然后重启docker:systemctl restart docker

docker info可以查看docker的信息,可以看到已经换源成功:

简单使用

# 下载镜像
docker pull image_name
# 运行镜像
docker run -d(后台运行) image_name

这里就以tomcat为例了:

在windows中用浏览器访问看能不能看到tomcat的欢迎界面:

显然是访问不到的,因为8080是linux的端口号,而容器内tomcat启动的tomcat端口号8080并没有映射到linux的8080,所以是访问不到的。需要通过**-p linux端口:容器端口**,来做一个映射,这样就可以访问到了。首先把tomcat停掉:

然后再重新启动,加上-p后再从浏览器进行访问:

tomcat是能访问到的,但是这个版本的tomcat webapps目录下没东西,不像之前有欢迎界面了… 很无语。

进入docker容器
docker exec -it container_id(name) bash

i表示交互式的,也就是保持标准输入输出流打开。t表示虚拟控制台,分配到一个虚拟控制台。

退出也很简单,直接exit就退出容器了。

但是每次都用ID很不方便,需要提前ps看ID。可以在运行的时候通过–name指定容器名字,这样后续的指令都可以用容器名字代替ID:

–name="my_tomcat"和–name my_tomcat都是可以的。

Docker核心组件

Docker使用客户端-服务器(C/S)架构模式,使用远程API来管理和创建Docker容器。

Docker容器通过Docker镜像来创建。镜像和容器的关系类似于面向对象中类和对象的关系:镜像就是类,容器就是对象。

Docker三个核心要素:镜像(Image)、容器(Container)、仓库(Repository)

镜像

Docker镜像就是一个只读的模板,用来创建Docker容器。

镜像是由许多层的文件系统叠加构成的:

最下面是一个引导文件系统bootfs,主要包含bootloader和kernel,这一层和linux系统是一样的,bootloader来加载内核。

第二层是一个root文件系统rootfs,rootfs是某种操作系统比如ubuntu centos,包含linux系统中的/dev /proc /bin等目录和文件。但是可以发现centos的镜像才200多M,因为它只需要包含最基本的命令(命令都是阉割过的 比如ll vim都没有)、工具和库就可以了,底层的kernel是可以直接用host的。

root文件系统之上有很多层文件系统,这些文件系统叠加在一起,构成docker中的镜像。

运行、进入、停止上面已经提过了。删除镜像是docker rmi image_name,注意不是rm,rm是删除容器。

容器

容器是从镜像创建的运行实例,可以被启动、停止、删除。每个容器都是相互隔离的、保证平台安全。可以看做一个简易版的linux环境,包括root用户权限、进程空间、用户空间、网络空间和运行在其中的应用程序。

Docker利用容器来运行应用,镜像是只读的,容器在启动的时候创建一层可写层作为最上层。

docker ps是查看正在运行中的容器,docker ps -a是查看所有的容器,包括之前已经stop的容器:

每次run都会新建一个容器,所以可以看到新建了四个tomcat容器,而且都是被stop了。现在通过start就可以将之前停掉的容器重新启动:

如果觉得开的容器太多了就可以通过docker rm container_id(name)来删除容器,删除的时候必须是停止状态。

查看容器更多信息:

docker inspect container_id(name)

只显示正在运行容器的ID:

docker ps -q

停用全部正在运行中的容器:

docker stop $(docker ps -q)

删除全部容器:

docker rm $(docker ps -aq)

然后两条命令也可以通过 & 拼在一起,实现一条命令停用并删除所有容器:

docker stop $(docker ps -q) & docker rm $(docker ps -aq)
commit镜像

通过上面的描述,可以了解到容器是在镜像之上增加了一个可写层,那如果希望把这个容器“打包”,让别人可以直接pull到这个已经修改过的镜像,就需要通过commit命令,和git是很相似的。

docker commit -m="提交的描述信息" -a="作者" 容器ID 目标镜像名:[TAG]

比如之前的tomcat里webapps目录下是空的,但是webapps.dist目录下有,我们可以手动把下面的东西拷到webapps目录下,这时再通过浏览器就可以访问了:

但是这个容器一旦被rm了,下次再启动一个新容器,还得手动拷贝,那就可以把这个容器提交了,下次用这个提交的镜像来新建容器,就不用再手动拷贝了。

这样下次通过自己commit的镜像新建容器,就不用手动拷贝东西了,后续还可以把这个镜像发布到阿里云仓库里,这样即使换了虚拟机也可以pull下来。

仓库

仓库是集中存放镜像文件的场所,有时候会把仓库和仓库注册服务器看做同一个事物,并不严格区分。实际上,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像都有不同的标签(tag)。

仓库分为公开仓库和私有仓库。最大的公开仓库是Docker Hub(https://hub.docker.com/),存放了数量庞大的镜像供用户下载。

用户也可以在本地网络创建一个私有仓库,之后就可以使用push命令将自己创建的镜像传到共有或者私有仓库。

部署nginx

先docker pull nginx,然后运行。在linux中新建一个test.html用来测试。先看一下nginx的html文件夹在哪个位置:

现在需要把linux中的test.html传到容器中的/usr/share/nginx/html文件夹下,命令为:docker cp。具体的格式可以通过–help查看:

然后在浏览器中访问:

容器数据卷

现在有一个需要解决的问题,就是容器中的数据怎么办,一旦容器删了,数据就没了。需要一种技术可以把容器中的数据同步到本地,而不是靠人工手动拷贝。

这就是容器数据卷的作用:将容器内的目录挂载到linux上

总结下来:容器的持久化和同步操作,容器间也是可以数据共享的

用法一:bind-mount 目录映射

docker run -v 主机目录:容器目录 ......

之后不论是在容器内还是容器外修改目录下的文件,都是同步的,应该是linux的硬链接,也就是文件只有一份。比如数据库就可以把data文件夹挂载到宿主机的目录下。

用法二:volume(匿名/具名挂载)

方法一是指定了一个主机目录,方法二则是不指定(匿名)/只指定一个名字(具名)。匿名的就不演示了,基本不会用,因为生成的名字是随机的。这里一定要区分,指定的名字开头没有 / ,这不代表是相对地址

使用方法二的,挂载点都在/var/lib/docker/volumes下,如果是匿名的那么文件夹名字就是随机生成的,具名的就是自己指定的名字:

-v 容器内路径 # 匿名挂载,docker给生成卷名
-v 卷名:容器内路径 # 具名挂载,路径为/var/lib/docker/volumes/卷名
-v /宿主机路径:容器内路径 # 指定路径挂载

容器路径后可以接上 :ro/rw  ro表示只读,rw表示可读可写。一旦限定了ro,那么容器就无法对这个文件夹进行写操作了,只能在宿主机进行修改。

Docker自定义镜像

Dockerfile用于构建Docker镜像,Dockerfile文件是由一行行命令语句组成,基于这些命令可以构建一个镜像。

一般Dockerfile分为四个部分:基础镜像信息;维护者信息;镜像操作指令;容器启动时执行指令。

Dockerfile指令:

FROM

格式为FROM <image> 或者 FROM <image>:<tag>。Dockerfile文件的第一条指令必须为FROM指令。并且如果在一个Dockerfile中创建多个镜像时,可以使用多个FROM指令(每个镜像一次)。

MAINTAINER

格式为 MAINTAINER <name>,指定维护者信息。

VOLUME

格式为 VOLUME [“volume_name01”, “volume_name02” …],会在创建容器时自动帮你挂载两个文件夹,容器内的文件夹名称就是指定的名字,宿主机内则还是/var/lib/docker/volumes/随机生成,也就是匿名挂载。

ENV

格式为 ENV <key> <value>,指定一个环境变量,会被后续RUN指令使用,并在容器运行时保持。

ADD

格式为 ADD <src> <dest>,复制指定的<src>到容器中的<dest>。

EXPOSE

格式为 EXPOSE <port> [<port> …],告诉Docker服务端暴露的端口号,供互联系统使用,在启动容器时需要通过 -p映射端口,Docker主机会自动分配一个端口转发到指定的端口。

RUN

格式为 RUN <command>,RUN指令将在当前镜像基础上执行指定命令,并提交为新的镜像,命令比较长的时候可以用 \ 来换行。

CMD

指定启动容器时执行的命令,每个Dockerfile只能有一条CMD命令。如果指定了多条CMD命令,只有最后一条会被执行。如果用户启动容器时指定了运行的命令,则会覆盖掉CMD指定的命令。

自定义centos镜像

vim mydockerfile

FROM centos
MAINTAINER youkee<xdutao@foxmail.com>

ENV MYPATH /usr/local
WORKDIR $MYPATH
 
RUN yum install -y vim
RUN yum install -y net-tools

EXPOSE 80

CMD echo $MYPATH
CMD echo "---end---"
CMD /bin/bash

然后在当前目录下:

docker build -f mydockerfile -t mycentos:0.1 .

最后一个 . 不要忘了表示在当前目录下。如果不想通过-f指定文件的路径,只要确保名字叫Dockerfile就可以了。

CMD和ENTRYPOINT区别

CMD:指定这个容器启动时要运行的命令,只有最后一个会生效,可被替代

ENTRYPOINT:指定这个容器启动时要运行的命令,可以追加命令

linux的ls命令可以追加多个参数,比如ls -a只列出来名字,再加个l参数 ls -al就会列举出详细信息:比如读写权限,大小,创建时间等。

现在假如Dockerfile是这么写的:

FROM centos
CMD ["ls", "-a"]

那么build成功后运行会列出工作目录下的所有文件名,如果在run的后面添加一个 -l,就会报错,提醒你 “-l不是一个可执行命令“,因为这里 -l 把 ls -a命令覆盖掉了。

如果Dockerfile是这么写的:

FROM centos
ENTRYPOINT ["ls", "-a"]

那么,run的时候在后面添加 -l,就会列出工作目录下所有文件的详细信息,也就是命令追加成了 ls -al。

自定义Tomcat镜像

需要准备好jdk和tomcat的压缩包

FROM centos
MAINTAINER youkee<xdutao@foxmail.com>

ADD jdk-11.0.10_linux-x64_bin.tar.gz /usr/local/
ADD apache-tomcat-9.0.44.tar.gz /usr/local/

RUN yum install -y vim

ENV MYPATH /usr/local
WORKDIR $MYPATH

ENV JAVA_HOME /usr/local/jdk-11.0.10
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.44
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.44
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin

EXPOSE 8080

CMD /usr/local/apache-tomcat-9.0.44/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.44/bin/logs/catalina.out

之后:

docker build -t diytomcat:1.0 .

然后把该镜像运行起来:

docker run -d -p 8080:8080 diytomcat:1.0

浏览器中访问正常:

这里一定要注意,用jdk 11。因为下的tomcat太新了,虽然官方文档上写的tomcat 9.x只要8以上的就可以,但是用jdk8的时候java -version一直提示没文件,tomcat启动不了。换成11才没问题。

发布镜像到阿里云

首先注册阿里云账号,用户名一定用英文的!不然到时候在控制台登录的时候打中文非常尴尬。

然后创建个人版实例,会让你设置registry密码,可以看到用户名就是阿里云账户名,如果是中文的就得在控制台输中文用户名,密码可以和登录密码一样也可以不一样,随意。

然后分别创建命名空间和镜像仓库,代码源可以关联github的仓库,也可以直接用本地仓库:

点进去就可以看到已经有文档告诉你怎么发布镜像了,按着提示来就可以:

这里就用helloword做测试了,别的镜像都太大了。

这时可以看控制台的镜像仓库已经有东西了:

退出登录docker logout就可以。

Docker网络

先用ip addr命令网络:

分别是本地回环地址、腾讯云内网地址和docker0地址。

下面运行一个tomcat,然后看一下在容器内部,它的ip地址是多少:

[root@VM-8-10-centos ~]# docker run -d -P --name tomcat01 tomcat

[root@VM-8-10-centos ~]# docker exec -it tomcat01 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
82: eth0@if83: <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

然后**在linux中ping容器内部的这个ip,显然是可以ping通的**,可以发现172.17.0.2是和docker0在同一个网段内的:

  • 每启动一个容器,docker就会给docker容器分配一个ip,只要安装了docker,就会有一个网卡docker0桥接模式,使用的是veth-pair技术。

  • 这时,我们运行着tomcat,再次ip addr,可以发现多了一个网卡:

    而且可以看到,网卡的开头83: veth510cdfd@if82和刚刚在容器内看ip地址时的网卡名惊人地相似82: eth0@if83

    然后,再运行一个tomcat,查看它的网络信息,发现还是成对出现的:

    在tomcat02中ping tomcat01,可以ping通,按理说容器之间是互相隔离的,但是这里却ping通了。

    这里的原理大致为:

但是这样还有一个缺陷,就是tomcat01是无法直接ping tomcat02的,必须ping ip地址,这个缺陷可以通过 --link参数解决:

其实–link的原理也很简单,就是在hosts文件中加了一行

这样配一两个容器还可以通过–link解决,但是如果要部署redis集群,需要很多容器,一个个link就太麻烦了,所以可以通过自定义网络来解决这个问题。

自定义网络

在创建容器时,默认使用的网络是bridge,我们可以自定义一个网络,然后创建容器时通过–net networkname显示指定使用的网络,自定义的网络相当于自带DNS,可以直接通过容器名ping通,在部署集群时非常方便。

docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet

然后通过命令查看现在的网络:

现在我们再新建两个tomcat容器,通过–net mynet显示指定网络,而不用–link进行连接。这时再inspect我们新建的网络,可以看到划分的网段就是我们定义的子网:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d4u4xKeL-1617802449327)(C:\Users\Youkee\AppData\Roaming\Typora\typora-user-images\image-20210407181119131.png)]

这时通过容器名相互ping都是通的:

现在tomcat01和tomcat02用的是docker0,tomcat03和tomcat04用的是mynet,在不同的网段,是肯定ping不通的:

但是docker提供了connect命令,可以打通容器和network:

docker network connect mynet tomcat01

这时再inspect一下mynet,会发现实现也很暴力,就是给tomcat01又分配了一个地址:

这时进入tomcat01,查看ip addr,会发现它比之前多了一个网卡:

然后ping mynet内的任何容器都是可以通的:

部署springboot项目

准备一个springboot的hello world,本地调试好打成jar包,然后编写Dockerfile

FROM java:8

COPY *.jar /app.jar

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "/app.jar"]

将jar包和Dockerfile放在一个文件夹下

然后:

docker build -t boot .

下java 8比较慢,需要等一会,build成功后直接run就行了:

docker run -d -p 8080:8080 boot

浏览器访问:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值