文章目录
docker命令基础框架
如图,docker所有操作基本上离不开镜像,那么镜像的操作都会,但是,镜像是怎么构成的呢?
对于镜像的作用和用途,如下
镜像
Docker的镜像 ( image ) 是创建容器的基础, 是一个只读模板,可以用来创建docker容器, 类似虚拟机的快照,可以理解为是一个面向 Docker容器引擎的只读模板。比如一个镜像可以是一个完整的 Centos操作系统环境,称为一个 Centos镜像:可以是一个安装了MySQL的应用程序,称为一个MySQL镜像,等等,我们可以把所需要的一切都打包成镜像, 打包后的镜像在某台机器上能运行,那它就能够在任何装有docker的机器上运行
下面还有对镜像的补充、、、、、
镜像是什么?
镜像是一种轻量级,可执行的独立软件包,用来打包软件的运行环境和基于运行环境开发的软件,它包含运行某个软件所需要的内容,包括代码,运行时,库,环境变量和配置文件。
联合文件系统(UnionFS)
了解镜像之前,先了解联合文件系统,docker镜像是一层一层叠上来的,每一层镜像都会有一个id,但是最后只会显示最后一层的id;有人说这种架构像是洋葱,有人能说像花卷,你认为呢???
UnionFS(联合文件系统):UnionFS文件系统是一种分层,轻量级并高性能的文件系统,它支持对文件系统的修改作为一次提交来一层一层的叠加,UnionFS文件系统是Docker镜像的基础,镜像可以通过分层来继承,基于基础镜像,可以做出各种的应用镜像。
docker镜像加载
docker镜像实际上有一层一层的文件系统组成,这种层次的文件系统(UnionFS)
我们知道docker和宿主机共享linux内核(kernel),其实原理是这样的:
linux启动会加载bootfs文件系统,所以docker镜像最底层也就是bootfs
当bootfs加载完成以后整个内核就会在内存,此时bootfs就没有用了,会被系统卸载;
rootfs就是典型的不同的linux系统的发行版,比如:Ubuntu,centos,包括/dev /proc /bin /etc/ …
对于一个docker精简的OS,rootfs可以很小,只需要最基本的命令,工具,程序库就可以了,但是底层kernel和宿主机一样,所以有人也说,每一个docker容器都是一个精简的linux环境。
docker镜像加载过程
镜像的分层
我们拉取一个镜像或者dockerfile生成一个镜像时都是这样一层一层的
那么为什么需要分层呢?
最大的好处——共享资源
也就是下面我们要说的docker镜像缓存特性
dockerfile构建镜像
- dockerfile的书写格式为:Dockerfile
- FROM: 构建镜像有两种方式,一种是scratch(从零构建),另一种可以基于某个镜像开始构建
- 镜像所运行的操作(用户自定义的)
编写一个简单的dockerfile
切记,一个目录默认只能运行一个Dockerfile,Default is 'PATH/Dockerfile',注意Dockerfile的格式,D要大写,不能错,除此之外,通过-f 指定dockerfile的文件名+绝对路径的方式也可以哦
[root@docker01 ~]# mkdir dockerfile && cd dockerfile
[root@docker01 dockerfile]# ls
Dockerfile
[root@docker01 dockerfile]# vim Dockerfile
FROM centos:7
RUN yum -y install vim
RUN yum -y install net-tools
CMD ["/bin/bash"]
基于dockerfile创建镜像
[root@docker01 ~]# docker build -t new02:centos /root/dockerfile
因为之前built过次镜像,所以出现这种情况
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM centos:7
---> b5b4d78bc90c
Step 2/4 : RUN yum -y install vim
---> Using cache
---> 7f5cb26c1891
Step 3/4 : RUN yum -y install net-tools
---> Using cache
---> 79d2860a90c1
Step 4/4 : CMD ["/bin/bash"]
---> Using cache
---> 7ffcfd3ab131
Successfully built 7ffcfd3ab131
Successfully tagged new02:centos
也证实了上面的提到的docker分层的好处
docker镜像缓存特性
缓存可以用的要求:
- 如果在相同的层,有用到相同的镜像,可以不必再去下载,直接使用缓存
- 必须是相同的层,相同的镜像
- 如果前边的层发生改变,即使后边的层操作和顺序一样,也不能使用 缓存特性
[root@docker01 ~]# docker build -t new02:centos /root/dockerfile --no-cache
dockerfile常用的指令 🐷
指令 | 作用 |
---|---|
FROM | 构建镜像基于哪个镜像 |
MAINTAINER | 镜像维护者姓名或邮箱地址 |
RUN | 构建镜像时运行的shell命令 |
CMD | 运行容器时 执行的shell命令 |
EXPOSE | 运行容器后 声明容器的服务端口 |
ENV | 设置容器环境变量 |
ADD | 拷贝文件或目录到镜像,会自动下载或自动解压 |
COPY | 拷贝文件或目录到镜像 |
VOLUME | 指定运行容器挂载点 到宿主机自动生成的目录(默认/var/lib/docker/volumes),类似manager volume挂载 |
USER | 为RUN、CMD、和ENTRYPOINT执行命令指定运行用户 |
WORKDIR | 类似linux的cd,容器运行后所在的目录 |
HEALTHCHECK | 健康检查 |
ENTRYPOINT | 运行容器时 执行的shell命令 |
PS注意事项:
1. RUN在building时运行,可以写多条。其实RUN是有条件限制的
2. CMD和ENTRYPOINT在运行container时运行,只能写一条,如果写多
条,最后一条生效
区别:
CMD “ls”,"a" 构建时在命令行里面不能在显示追加的内容
ENTRYPORT “ls”,"a" 构建的时候在命令行可以显示追加内容例如:docker run -it id -l
3. 如果在Dockerfile里需要往镜像内导入文件,则,此文件必须在
dockerfile所在目录或子目录下
4. 一个目录下,只能有一个Dockerfile文件,并且名称的大小写严格按照
要求: Dockerfile.
例子:Dockerfile构建nginx
基于centos7的环境搭建nginx
FROM centos:7
RUN yum -y install gcc pcre pcre-devel zlib zlib-devel openssl openssl-devel
COPY nginx-1.17.5.tar.gz /usr/local
WORKDIR /usr/local/
RUN tar -zxf /usr/local/nginx-1.17.5.tar.gz
RUN useradd -M -s /sbin/nologin nginx
WORKDIR /usr/local/nginx-1.17.5/
RUN ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx && make && make install
WORKDIR /root
RUN ln -s /usr/local/nginx/sbin/* /usr/local/sbin/
RUN nginx -t
RUN nginx
EXPOSE 80
COPY index.html /usr/local/nginx/html/
#CMD [ "nginx" "-g" "daemon off" ]
默认开启进入容器的的时候,nginx不会开启,需要添加 nginx -g "daemon off"
[root@docker01 t5]# docker built -t dc05:nginx .
[root@docker01 t5]# docker run -itd --name dc10 dc05:nginx nginx -g "daemon off;"
2b691183e572300b01dc565860ea97eaa28574a8b2f651f4010ea094d81b7e41
[root@docker01 t5]# docker exec -it dc10 /bin/bash
[root@2b691183e572 ~]#
[root@2b691183e572 ~]# curl 127.0.0.1
123.com
dockerfile构建httpd
基于centos:7 🦌
FROM centos:7
RUN yum -y install httpd
ENV dir=/var/www/html/index.html
COPY index.html $dir
ADD run.sh /root/run.sh
RUN chmod 755 /root/run.sh
EXPOSE 80
CMD ["/root/run.sh"]
开启容器时启动httpd,vim run.sh
#!/bin/bash
exec /usr/sbin/httpd -D FOREGROUND #前台开启httpd
基于httpd镜像构建
FROM httpd:latest
ENV dir=/usr/local/apache2/htdocs/index.html
COPY index.html $dir
EXPOSE 80
dockerfile 构建tomcat
FROM centos:7
ADD apache-tomcat-8.5.55.tar.gz /usr/local/
ADD jdk-8u261-linux-x64.tar.gz /usr/local/
RUN yum -y install vim
ENV MYPATH /usr/local
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk1.8.0_261
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-8.5.55
ENV CATALINA_BASH /usr/local/apache-tomcat-8.5.55
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
EXPOSE 8080
CMD ["/usr/local/apache-tomcat-8.5.55/bin/catalina.sh","run"]
构建镜像
[root@docker01 ~]# docker build -t mytomcat /tomcat/
根据这个 镜像启动一个容器
[root@docker01 ~]# docker run -itd --name dc02 -P -v /root/tomcat/test:/usr/local/apache-tomcat-8.5.55/webapps/test -v /var/log/tomcat:/usr/local/apache-tomcat-8.5.55/logs mytomcat
模拟部署一个项目发布
做了目录挂载,所以项目部署在宿主机即可
需要在宿主机提添加WEB-INF和web.xml
[root@docker01 test]# mkdir WEB-INF
[root@docker01 test]# ls
WEB-INF
[root@docker01 test]# cd WEB-INF/
[root@docker01 WEB-INF]# vim web.xml
[root@docker01 WEB-INF]# cd ..
[root@docker01 test]# vim index.jsp
随便摘一个web.xml
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<description> Test App</description>
</web-app>
写一个jsp的测试页
print time <%=new java.util.Date()%>
docker构建redis高可用集群
拉取redis的官方镜像
docker pull redis
在宿主机上创建redis的数据文件和配置文件;
#!/bin/bash
for port in $(seq 1 6)
do
mkdir -p /opt/redis_cluster/redis_node${port}_6379/conf
mkdir -p /data/redis_cluster/redis_node${port}_6379
cat > /opt/redis_cluster/redis_node${port}_6379/conf/redis_node${port}_6379.conf << EOF
bind 0.0.0.0
port 6379
cluster-enabled yes
cluster-config-file clusters_6379.conf
cluster-node-timeout 15000
cluster-announce-ip 172.16.0.1$port
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
appendfilename "redis_node${port}_6379.aof"
appendfsync everysec
EOF
done
启动redis容器
docker run -p 6371:6379 -p 16371:16379 --name redis-1 -v /opt/redis_cluster/redis_node1_6379/conf/redis_node1_6379.conf:/etc/redis/redis.conf -v /data/redis_cluster/redis_node1_6379:/data -d --net redis --ip 172.16.0.11 redis:latest redis-server /etc/redis/redis.conf
脚本创建redis容器
for port in $(seq 1 6)
do
docker run -itd -p 637${port}:6379 -p 1637${port}:16379 --name redis-${port} -v /opt/redis_cluster/redis_node${port}_6379/conf/redis_node${port}_6379.conf:/etc/redis/redis.conf -v /data/redis_cluster/redis_node${port}_6379:/data -d --net redis --ip 172.16.0.1${port} redis:latest redis-server /etc/redis/redis.conf
done
进入redis,创建redis高可用集群
[root@docker01 ~]# docker exec -it redis-1 /bin/bash
root@d2dcc044beac:/data# redis-cli --cluster create 172.16.0.11:6379 172.16.0.12:6379 172.16.0.13:6379 172.16.0.14:6379 172.16.0.15:6379 172.16.0.16:6379 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.16.0.15:6379 to 172.16.0.11:6379
Adding replica 172.16.0.16:6379 to 172.16.0.12:6379
Adding replica 172.16.0.14:6379 to 172.16.0.13:6379
M: 19c9265cf4becb247852ac0a14a005f253db107d 172.16.0.11:6379
slots:[0-5460] (5461 slots) master
M: cf3cecfe839469f5b67524ffa01a81e808ce73de 172.16.0.12:6379
slots:[5461-10922] (5462 slots) master
M: 9a9a1ae0056cf6bff9fbf0d970f83c9a77d88792 172.16.0.13:6379
slots:[10923-16383] (5461 slots) master
S: 9ddbc99ff157c146a5896b1e51ce4cbc861dbea6 172.16.0.14:6379
replicates 9a9a1ae0056cf6bff9fbf0d970f83c9a77d88792
S: 7548e76a8a580b1987650c5de3b489f50b6ad935 172.16.0.15:6379
replicates 19c9265cf4becb247852ac0a14a005f253db107d
S: c2146da9e2474fed1cd461e325ab00698e4a95f0 172.16.0.16:6379
replicates cf3cecfe839469f5b67524ffa01a81e808ce73de
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
.
>>> Performing Cluster Check (using node 172.16.0.11:6379)
M: 19c9265cf4becb247852ac0a14a005f253db107d 172.16.0.11:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: 7548e76a8a580b1987650c5de3b489f50b6ad935 172.16.0.15:6379
slots: (0 slots) slave
replicates 19c9265cf4becb247852ac0a14a005f253db107d
M: cf3cecfe839469f5b67524ffa01a81e808ce73de 172.16.0.12:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: 9ddbc99ff157c146a5896b1e51ce4cbc861dbea6 172.16.0.14:6379
slots: (0 slots) slave
replicates 9a9a1ae0056cf6bff9fbf0d970f83c9a77d88792
M: 9a9a1ae0056cf6bff9fbf0d970f83c9a77d88792 172.16.0.13:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: c2146da9e2474fed1cd461e325ab00698e4a95f0 172.16.0.16:6379
slots: (0 slots) slave
replicates cf3cecfe839469f5b67524ffa01a81e808ce73de
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
验证集群
root@d2dcc044beac:/data# redis-cli -c -h 172.16.0.16 -p 6379
172.16.0.16:6379> set k1 v1
-> Redirected to slot [12706] located at 172.16.0.13:6379
OK
172.16.0.13:6379> set k2 v2
-> Redirected to slot [449] located at 172.16.0.11:6379
OK
172.16.0.11:6379> get k1
-> Redirected to slot [12706] located at 172.16.0.13:6379
"v1"
172.16.0.13:6379> get k2
-> Redirected to slot [449] located at 172.16.0.11:6379
"v2"
172.16.0.11:6379>
验证高可用
# 验证高可用,停掉redis-3 master
[root@docker01 ~]# docker stop redis-3
redis-3
172.16.0.16:6379> CLUSTER NODES
7548e76a8a580b1987650c5de3b489f50b6ad935 172.16.0.15:6379@16379 slave 19c9265cf4becb247852ac0a14a005f253db
19c9265cf4becb247852ac0a14a005f253db107d 172.16.0.11:6379@16379 master - 0 1596082825000 1 connected 0-546
cf3cecfe839469f5b67524ffa01a81e808ce73de 172.16.0.12:6379@16379 master - 0 1596082824000 2 connected 5461-
9ddbc99ff157c146a5896b1e51ce4cbc861dbea6 172.16.0.14:6379@16379 master - 0 1596082821731 7 connected 10923
9a9a1ae0056cf6bff9fbf0d970f83c9a77d88792 172.16.0.13:6379@16379 master,fail - 1596082761527 1596082758000
c2146da9e2474fed1cd461e325ab00698e4a95f0 172.16.0.16:6379@16379 myself,slave cf3cecfe839469f5b67524ffa01a8
172.16.0.16:6379>
#再次获取数据,原来放到redis-3的k1已经放到了redis-4上
root@d2dcc044beac:/data# redis-cli -c -h 172.16.0.14 -p 6379
172.16.0.14:6379> get k1
"v1"
oK,完成!🐒