Docker详解(上)(三)

本文涉及的产品
云数据库 Redis 版,标准版 2GB
推荐场景:
搭建游戏排行榜
云原生内存数据库 Tair,内存型 2GB
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: Docker详解(上)

DockerFile


DockerFile介绍


DockerFile是用来构建docker镜像的文件!命令参数脚本!


构建步骤:


  1. 编写一个dockerfile文件


  1. docker build 构建成为一个镜像


  1. docker run 运行镜像


  1. docker push 发布镜像(DockerHub、阿里云镜像仓库!)


查看一下官方是怎么做的?


image.png

image.png


发现官方的镜像都是基础包,很多功能没有,我们通常会自己搭建自己的镜像!

官方既然可以制作镜像,那么我们也可以!


DockerFile构建过程


基础知识:


  1. 每个保留关键字(指令)都是必须是大写字母


  1. 执行从上到下顺序执行


  1. # 表示注释


  1. 每一个指令都会创建提交一个新的镜像层,并提交!


image.png


DockerFile是面向开发的,我们以后要发布项目,做镜像,就需要编写dockerfile文件,这个文件十分简单!


Docker镜像逐渐成为企业交付的标准,必须要掌握!


步骤:开发,部署,运维。。。缺一不可!


DockerFile:构建文件,定义了一切的步骤,源代码


DockerImages:通过DockerFile构建生成的镜像,最终发布和运行的产品!


Docker容器:容器就是镜像运行起来提供服务的


DockerFile的指令


以前的话我们就是使用别人的,现在我们知道了这些指令后,我们来练习自己写一个镜像!


FROM        # 基础镜像,一切从这里开始构建
MAINTAINER  # 镜像是谁写的,姓名+邮箱
RUN         # 镜像构建的时候需要运行的命令
ADD         # 步骤,tomcat镜像,这个tomcat压缩包!添加内容
WORKDIR     # 镜像的工作目录
VOLUME      # 挂载的目录
EXPOSE      # 暴露端口配置
CMD         # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT  # 指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD     # 当构建一个被继承的 DockerFile 这个时候就会运行 ONBUILD 的指令,触发指令
COPY        # 类似ADD,将我们的文件拷贝到镜像中
ENV         # 构建的时候设置环境变量!


image.png


实战测试


Docker Hub中99%镜像都是从这个基础镜像过来的 FROM scratch,然后配置需要的软件和配置来进行构建


image.png


创建一个自己的centos


创建出错可以查看我的博客中遇到的错误一栏中的相关内容进行解决!


# 1 编写Dockerfile的文件
[root@ls-Cwj2oH9C dockerfile]# cat mydockerfile-centos
FROM centos:7.9.2009
MAINTAINER wydilearn<406623380@qq.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum install vim
RUN yum install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "----end----"
CMD /bin/bash
# 2 通过这个文件构建镜像
# 命令 docker build -f dockerfile文件路径 -t 镜像名:[tag]
Successfully built 4ca77dadd64f
Successfully tagged mycentos:7.9.2009
# 3 测试运行


对比:之前的原生centos


工作目录默认是根目录,没有vim、ifconfig等命令


我们增加之后的镜像:


image.png


我们可以列出本地镜像的变更历史


image.png


我们平时拿到一个镜像,可以研究一下它是怎么做的了!


CMD 和 ENTRYPOINT 区别


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


测试cmd


# 编写 dockerfile 文件
[root@ls-Cwj2oH9C dockerfile]# vim dockerfile-cmd-test
FROM centos
CMD ["ls","-a"]
# 构建镜像
[root@ls-Cwj2oH9C dockerfile]# docker build -f dockerfile-cmd-test -t cmdtest .
# run运行,发现我们的ls -a 命令生效
[root@ls-Cwj2oH9C dockerfile]# docker run 08f5a6379ff7
.
..
.dockerenv
anaconda-post.log
bin
dev
etc
home
lib
lib64
# 想追加一个命令 -l  ls -al
[root@ls-Cwj2oH9C dockerfile]# docker run 08f5a6379ff7 -l
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "-l": executable file not found in $PATH: unknown.
ERRO[0000] error waiting for container: context canceled 
# CMD的情况下 -l 替换了CMD ["ls","-a"]命令,-l 不是命令所以报错!


测试 ENTRYPOINT


[root@ls-Cwj2oH9C dockerfile]# vim dockerfile-cmd-entrypoint
FROM centos:7.9.2009
ENTRYPOINT ["ls","-a"]
[root@ls-Cwj2oH9C dockerfile]# docker build -f dockerfile-cmd-entrypoint -t entrypoint-test .
Sending build context to Docker daemon  4.096kB
Step 1/2 : FROM centos:7.9.2009
 ---> eeb6ee3f44bd
Step 2/2 : ENTRYPOINT ["ls","-a"]
 ---> Running in a11a899f08f4
Removing intermediate container a11a899f08f4
 ---> db46b6b11456
Successfully built db46b6b11456
Successfully tagged entrypoint-test:latest
[root@ls-Cwj2oH9C dockerfile]# docker run d74cdaf8abb6
.
..
.dockerenv
anaconda-post.log
bin
dev
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
# 我们的追加命令,是直接拼接在我们的 ENTRYPOINT 命令的后面!
[root@ls-Cwj2oH9C dockerfile]# docker run d74cdaf8abb6 -l
total 64
drwxr-xr-x   1 root root  4096 Jul 12 08:56 .
drwxr-xr-x   1 root root  4096 Jul 12 08:56 ..
-rwxr-xr-x   1 root root     0 Jul 12 08:56 .dockerenv
-rw-r--r--   1 root root 12114 Nov 13  2020 anaconda-post.log
lrwxrwxrwx   1 root root     7 Nov 13  2020 bin -> usr/bin
drwxr-xr-x   5 root root   340 Jul 12 08:56 dev
drwxr-xr-x   1 root root  4096 Jul 12 08:56 etc
drwxr-xr-x   2 root root  4096 Apr 11  2018 home
lrwxrwxrwx   1 root root     7 Nov 13  2020 lib -> usr/lib
lrwxrwxrwx   1 root root     9 Nov 13  2020 lib64 -> usr/lib64
drwxr-xr-x   2 root root  4096 Apr 11  2018 media
drwxr-xr-x   2 root root  4096 Apr 11  2018 mnt
drwxr-xr-x   2 root root  4096 Apr 11  2018 opt
dr-xr-xr-x 173 root root     0 Jul 12 08:56 proc
dr-xr-x---   2 root root  4096 Nov 13  2020 root
drwxr-xr-x  11 root root  4096 Nov 13  2020 run
lrwxrwxrwx   1 root root     8 Nov 13  2020 sbin -> usr/sbin
drwxr-xr-x   2 root root  4096 Apr 11  2018 srv
dr-xr-xr-x  13 root root     0 Jul  9 02:03 sys
drwxrwxrwt   7 root root  4096 Nov 13  2020 tmp
drwxr-xr-x  13 root root  4096 Nov 13  2020 usr
drwxr-xr-x  18 root root  4096 Nov 13  2020 var


Dockerfile中很多命令都十分的相似,我们需要了解它们的区别,我们最好的学习就是对比他们然后测试效果!


实战:Tomcat镜像


  1. 准备镜像文件 tomcat 压缩包,jdk的压缩包!

image.png


  1. 编写dockerfile文件,官方命名 Dockerfile ,build 会自动寻找这个文件,就不需要 -f 指定了!


FROM centos:7.9.2009
MAINTAINER wydilearn<406623380@qq.com>
COPY readme.txt /usr/local/readme.txt
ADD jdk-8u333-linux-x64.tar /usr/local/
ADD apache-tomcat-10.0.22.tar.gz /usr/local/
RUN yum -y install vim
ENV MYPATH /usr/local
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk1.8.0_333
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-10.0.22
ENV CATALINA_BASE /usr/local/apache-tomcat-10.0.22
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
EXPOSE 8080
CMD /usr/local/apache-tomcat-10.0.22/bin/startup.sh && tail -F /usr/local/apache-tomcat-10.0.22/bin
/logs/catalina.out


  1. 构建镜像


# docker build -t diytomcat .


  1. 启动镜像


  1. 访问测试


  1. 发布项目(由于做了卷挂载,我们直接在本地编写项目就可以发布了!)


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                             http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         id="WebApp_ID" version="2.5">
</web-app>


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>hello,kuangshen</title>
</head>
<body>
Hello World!<br/>
<%
System.out.println("----my test web logs----");
%>
</body>
</html>


发现:项目部署成功,可以直接访问ok!


我们以后开发的步骤:需要掌握Dockerfile的编写!我们之后的一切都是使用docker镜像来发布运行!


发布自己的镜像


DockerHub


  1. 地址 https://hub.docker.com/ 注册自己的账号!


  1. 确定这个账号可以登录


  1. 在我们的服务器上提交自己的镜像


[root@ls-Cwj2oH9C tomcatlogs]# docker login --help
Usage:  docker login [OPTIONS] [SERVER]
Log in to a Docker registry.
If no server is specified, the default is defined by the daemon.
Options:
  -p, --password string   Password
      --password-stdin    Take the password from stdin
  -u, --username string   Username


  1. 登录完毕后就可以提交镜像了,就是一步 docker push


# 给自己要发布的镜像增加一个 tag
[root@ls-Cwj2oH9C tomcat]# docker tag 52f83276fc08 wydilearn/diytomcat:1.0
# docker push上去即可!自己发布的镜像尽量带上版本号
[root@ls-Cwj2oH9C tomcat]# docker push wydilearn/diytomcat:1.0
The push refers to repository [docker.io/wydilearn/diytomcat]
3c40fff9f2ee: Pushed 
fc3bd8b32ed0: Pushed 
f8c82bfdcfb9: Pushed 
a5760cf5dc3b: Pushed 
174f56854903: Mounted from library/centos 
1.0: digest: sha256:e0fae8f6383fdbf05a1fc89676fd7696949fc16d378f698a60918cb16a0fabb9 size: 1373


image.png


提交的时候也是按照镜像的层级来进行提交的。


发布到阿里云镜像服务上


  1. 登录阿里云


  1. 找到容器镜像服务


  1. 创建命名空间

image.png


  1. 创建容器镜像

image.png


  1. 浏览阿里云

image.png


阿里云容器镜像就参考官方地址!


小结


image.png


Docker 网络


理解Docker0


清空所有环境


测试


image.png


三个网络


# 问题:docker 是如何处理容器网络访问的?


image.png


[root@ls-Cwj2oH9C /]# docker run -d -P --name tomcat01 tomcat
# 查看容器的内部网络地址 ip addr,发现容器启动的时候会得到一个 eth0@if2763 IP地址,docker分配的!
[root@ls-Cwj2oH9C /]# docker exec -it 232419b4b0ff /bin/bash  # 进入容器安装两个命令
root@232419b4b0ff:/usr/local/tomcat# apt update && apt install -y iproute2
root@232419b4b0ff:/usr/local/tomcat# apt install iputils-ping
root@232419b4b0ff:/usr/local/tomcat# 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
2762: eth0@if2763: <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通容器内部!
[root@ls-Cwj2oH9C /]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.047 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.044 ms
# linux可以ping通容器内部


原理


  1. 我们每启动一个docker容器,docker就会给docker容器分配一个IP,我们只要安装了docker,就会有一个网卡 docker0


桥接模式,使用的技术是 evth-pair 技术!


再次测试ip addr

image.png


  1. 再启动一个容器测试,发现又多了一对网卡!


image.png


# 我们发现这个容器带来网卡,都是一对一对的
# evth-pair 就是一堆的虚拟设备接口,他们都是成对出现的,一端连着协议,一端彼此相连
# 正因为有这个特性,evth-pair充当一个桥梁,连接各种虚拟网络设备
# OpenStac,Docker容器之间的连接,OVS的连接,都是使用evth-pair技术


  1. 我们来测试下tomcat01和tomcat02是否可以ping通!


# 进入tomcat02
[root@ls-Cwj2oH9C /]# docker exec -it tomcat02 /bin/bash
root@fde1226260aa:/usr/local/tomcat# apt update && apt install -y iproute2
root@fde1226260aa:/usr/local/tomcat# apt install iputils-ping
root@fde1226260aa:/usr/local/tomcat# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.087 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.071 ms


结论:容器和容器之间是可以互相ping通的!


绘制一个网络模型图:


image.png

结论:tomcat01 和 tomcat02 是共用的一个路由器,docker0。


所有的容器不指定网络的情况下,都是 docker0 路由的,docker会给我们的容器分配一个默认的可用IP


小结


image.png


Docker中的所有网络接口都是虚拟的。虚拟的转发效率高!


只要容器删除,对应的一对网桥就没了!


image.png


--link


思考一个场景,我们编写了一个微服务,database url=ip:,项目不重启数据库ip换掉了,我们希望可以处理这个问题,可以通过名字来进行访问容器?


[root@ls-Cwj2oH9C ~]# docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known
# 如何可以解决呢?
# 通过--link 就可以解决网络连通问题
[root@ls-Cwj2oH9C ~]# docker run -it -d -P --name tomcat03 --link tomcat02 tomcat
371f584079471c6b8934c5ee961d741dba06884e0e85135bd0d224f685f0d6ca
[root@ls-Cwj2oH9C ~]# docker exec -it tomcat03 /bin/bash
root@371f58407947:/usr/local/tomcat# apt update && apt install -y iproute2
root@371f58407947:/usr/local/tomcat# apt install iputils-ping
root@371f58407947:/usr/local/tomcat# ping tomcat02
PING tomcat02 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.111 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.062 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=3 ttl=64 time=0.061 ms


探究:inspect!


image.png


其实这个tomcat03就是在本地配置了tomcat02配置


# 查看 hosts 配置,在这里原理发现!
[root@ls-Cwj2oH9C ~]# docker exec -it tomcat03 /bin/bash
root@371f58407947:/usr/local/tomcat# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3  tomcat02 fde1226260aa
172.17.0.4  371f58407947


本质探究:--link 就是在hosts配置中增加了一个 172.17.0.3 tomcat02 fde1226260aa

我们现在用Docker,已经不建议使用 --link 了!


自定义网络!不使用docker0!


docker0的问题:它不支持容器名连接访问!


自定义网络


查看所有的docker网络


image.png


网络模式


bridge:桥接模式 docker(默认,自己创建也使用 bridge 桥接模式)


none:不配置网络


host:和宿主机共享网络


container:容器内网络连通!(用的较少!局限很大)


三种常见网络模式(补充)


bridged(桥接模式)


虚拟机和宿主计算机处于同等地位,虚拟机就像是一台真实主机一样存在于局域网中

NAT(网络地址转换模式)


宿主计算机相当于一台开启了DHCP功能的路由器,而虚拟机则是内网中的一台真实主机

host-only(仅主机模式)


相当于虚拟机通过双绞线和宿主计算机直连,而宿主计算机不提供任何路由服务。因此在Host-only模式下,虚拟机可以和宿主计算机互相访问,但是虚拟机无法访问外部网络。


测试


# 我们直接启动的命令 --net bridge,而这个就是我们的docker0
[root@ls-Cwj2oH9C /]# docker run -d -P --name tomcat01 tomcat
[root@ls-Cwj2oH9C /]# docker run -d -P --name tomcat01 --net bridge tomcat
# docker0特点,默认,域名不能访问,--link可以打通连接!
# 我们可以自定义一个网络!
# --driver bridge
# --subnet 192.168.0.0/16  192.168.0.2 192.168.255.255
# --gateway 192.168.0.1
[root@ls-Cwj2oH9C /]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
c82c2708387b95f0d932ae395fe0dc1d3182d38a47b820584c66e39219541eb4
[root@ls-Cwj2oH9C /]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
1340a553ba22   bridge    bridge    local
6f12b7793243   host      host      local
c82c2708387b   mynet     bridge    local
2581ba94b5d9   none      null      local


我们自己的网络就创建好了!


image.png


[root@ls-Cwj2oH9C /]# docker run -d -P --name tomcat-net-01 --net mynet tomcat
e1d698bdf7bd90daf158e00e7f3c69785590198b477e1b45ef0fb2f6d2dd8ed6
[root@ls-Cwj2oH9C /]# docker run -d -P --name tomcat-net-02 --net mynet tomcat
685b7164f606200c809c81858a291374171ed2ddf77e30e24f94fbbbbcdbe2e1
[root@ls-Cwj2oH9C /]# docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "c82c2708387b95f0d932ae395fe0dc1d3182d38a47b820584c66e39219541eb4",
        "Created": "2022-07-16T17:38:25.818266785+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.0.0/16",
                    "Gateway": "192.168.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "685b7164f606200c809c81858a291374171ed2ddf77e30e24f94fbbbbcdbe2e1": {
                "Name": "tomcat-net-02",
                "EndpointID": "7a3ac62a87388c10907bee1b83800d28968caf47160bec9999c3921a3e5183ff",
                "MacAddress": "02:42:c0:a8:00:03",
                "IPv4Address": "192.168.0.3/16",
                "IPv6Address": ""
            },
            "e1d698bdf7bd90daf158e00e7f3c69785590198b477e1b45ef0fb2f6d2dd8ed6": {
                "Name": "tomcat-net-01",
                "EndpointID": "ea12cb9879b8d6801eabd3510e67e3a546888723ea743eedaec5274cca080ff0",
                "MacAddress": "02:42:c0:a8:00:02",
                "IPv4Address": "192.168.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]
# 再次测试ping连接
[root@ls-Cwj2oH9C ~]# docker exec -it tomcat-net-01 ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.085 ms
64 bytes from 192.168.0.3: icmp_seq=2 ttl=64 time=0.070 ms
# 现在不使用--link也可以ping名字了!
[root@ls-Cwj2oH9C ~]# docker exec -it tomcat-net-01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.055 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.063 ms


我们自定义的网络docker都已经帮我们维护好了对应的关系,推荐我们平时这样使用网络!


好处:


redis - 不同的集群使用不同的网络,保证集群是安全和健康的


mysql - 不同的集群使用不同的网络,保证集群是安全和健康的


网络连通


image.png

image.png


# 测试打通 tomcat01 - mynet
# 连通之后就是将 tomcat01 放到了 mynet 网络下
# 一个容器两个ip地址!
# 阿里云服务:公网ip  私网ip


image.png


# 01 连通ok
[root@ls-Cwj2oH9C ~]# docker exec -it tomcat01 ping tomcat-net-01
PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.072 ms
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.070 ms
# 02 是依旧打不通的
[root@ls-Cwj2oH9C ~]# docker exec -it tomcat02 ping tomcat-net-01
ping: tomcat-net-01: Name or service not known


结论:假设要跨网络操作别人,就需要使用 docker network connect 连通!


实战:部署Redis集群


image.png


shell脚本


# 创建网卡
[root@ls-Cwj2oH9C /]# docker network create redis --subnet 172.38.0.0/16
# 通过脚本创建六个redis配置
[root@ls-Cwj2oH9C /]# for port in $(seq 1 6); \
> do \
> mkdir -p /mydata/redis/node-${port}/conf
> touch /mydata/redis/node-${port}/conf/redis.conf
> cat << EOF >/mydata/redis/node-${port}/conf/redis.conf
> port 6379
> bind 0.0.0.0
> cluster-enabled yes
> cluster-config-file nodes.conf
> cluster-node-timeout 5000
> cluster-announce-ip 172.38.0.1${port}
> cluster-announce-port 6379
> cluster-announce-bus-port 16379
> appendonly yes
> EOF
> done
[root@ls-Cwj2oH9C conf]# docker run -p 6371:6379 -p 16371:16379 --name redis-1 \
> -v /mydata/redis/node-1/data:/data \
> -v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf \
> -d --net redis --ip 172.38.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
[root@ls-Cwj2oH9C conf]# docker run -p 6372:6379 -p 16372:16379 --name redis-2 \
> -v /mydata/redis/node-2/data:/data \
> -v /mydata/redis/node-2/conf/redis.conf:/etc/redis/redis.conf \
> -d --net redis --ip 172.38.0.12 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
[root@ls-Cwj2oH9C conf]# docker run -p 6373:6379 -p 16373:16379 --name redis-3 \
> -v /mydata/redis/node-3/data:/data \
> -v /mydata/redis/node-3/conf/redis.conf:/etc/redis/redis.conf \
> -d --net redis --ip 172.38.0.13 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
[root@ls-Cwj2oH9C conf]# docker run -p 6374:6379 -p 16374:16379 --name redis-4 \
> -v /mydata/redis/node-4/data:/data \
> -v /mydata/redis/node-4/conf/redis.conf:/etc/redis/redis.conf \
> -d --net redis --ip 172.38.0.14 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
[root@ls-Cwj2oH9C conf]# docker run -p 6375:6379 -p 16375:16379 --name redis-5 \
> -v /mydata/redis/node-5/data:/data \
> -v /mydata/redis/node-5/conf/redis.conf:/etc/redis/redis.conf \
> -d --net redis --ip 172.38.0.15 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
[root@ls-Cwj2oH9C conf]# docker run -p 6376:6379 -p 16376:16379 --name redis-6 \
> -v /mydata/redis/node-6/data:/data \
> -v /mydata/redis/node-6/conf/redis.conf:/etc/redis/redis.conf \
> -d --net redis --ip 172.38.0.16 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
# 任意进入一个reids容器,注意使用 /bin/sh 而不是 /bin/bash
[root@ls-Cwj2oH9C conf]# docker exec -it redis-1 /bin/sh
# 创建集群
/data # redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6
379 172.38.0.15:6379 172.38.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.38.0.15:6379 to 172.38.0.11:6379
Adding replica 172.38.0.16:6379 to 172.38.0.12:6379
Adding replica 172.38.0.14:6379 to 172.38.0.13:6379
M: f142bdcc5c5d7ac81eb70d91da9987b71a79d2e2 172.38.0.11:6379
   slots:[0-5460] (5461 slots) master
M: 3ab93307a4de5df775702779665ca4583abe5210 172.38.0.12:6379
   slots:[5461-10922] (5462 slots) master
M: abe4ba6a98b5fe967d952ffc06060d7c07474821 172.38.0.13:6379
   slots:[10923-16383] (5461 slots) master
S: ca57da80daea08a065f5add0a607edde9d11e7eb 172.38.0.14:6379
   replicates abe4ba6a98b5fe967d952ffc06060d7c07474821
S: e9664d81440a18689a1d8cd00f7a191f78f0979c 172.38.0.15:6379
   replicates f142bdcc5c5d7ac81eb70d91da9987b71a79d2e2
S: f972b8b774941d383a26ab31cc337c5017657ba0 172.38.0.16:6379
   replicates 3ab93307a4de5df775702779665ca4583abe5210
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.38.0.11:6379)
M: f142bdcc5c5d7ac81eb70d91da9987b71a79d2e2 172.38.0.11:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: abe4ba6a98b5fe967d952ffc06060d7c07474821 172.38.0.13:6379
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: ca57da80daea08a065f5add0a607edde9d11e7eb 172.38.0.14:6379
   slots: (0 slots) slave
   replicates abe4ba6a98b5fe967d952ffc06060d7c07474821
S: f972b8b774941d383a26ab31cc337c5017657ba0 172.38.0.16:6379
   slots: (0 slots) slave
   replicates 3ab93307a4de5df775702779665ca4583abe5210
S: e9664d81440a18689a1d8cd00f7a191f78f0979c 172.38.0.15:6379
   slots: (0 slots) slave
   replicates f142bdcc5c5d7ac81eb70d91da9987b71a79d2e2
M: 3ab93307a4de5df775702779665ca4583abe5210 172.38.0.12:6379
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
/data # redis-cli -c
127.0.0.1:6379> cluster info
127.0.0.1:6379> cluster nodes
127.0.0.1:6379> set a b
[root@ls-Cwj2oH9C ~]# docker stop redis-3
redis-3
127.0.0.1:6379> get a
-> Redirected to slot [15495] located at 172.38.0.14:6379
"b"


docker搭建redis集群完成!


image.png


我们使用了docker之后,所有的技术都会慢慢的变得简单起来!


SpringBoot微服务打包Docker镜像


  1. 构建springboot项目


@RestController
public class HelloController {
    @RequestMapping("/hello")
    public String hello(){
        return "hello,wydilearn";
    }
}


  1. 打包应用

image.png


  1. 编写dockerfile


FROM java:8
COPY *.jar /app.jar
CMD ["--server.port=8080"]
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]


  1. 构建镜像


[root@ls-Cwj2oH9C home]# mkdir idea
[root@ls-Cwj2oH9C home]# cd idea
[root@ls-Cwj2oH9C idea]# ls
demo1-0.0.1-SNAPSHOT.jar  Dockerfile
[root@ls-Cwj2oH9C idea]# docker build -t wydilearn .


  1. 发布运行!


[root@ls-Cwj2oH9C idea]# docker run -d -P --name wydilearn-springboot-web wydilearn
cd4d8f37d9e980af091eceac6ef30f51b9291fc415c53457285353881e19f84b
[root@ls-Cwj2oH9C idea]# docker ps
CONTAINER ID   IMAGE       COMMAND                  CREATED          STATUS          PORTS                                         NAMES
cd4d8f37d9e9   wydilearn   "java -jar /app.jar …"   37 seconds ago   Up 36 seconds   0.0.0.0:49163->8080/tcp, :::49163->8080/tcp   wydilearn-springboot-web
[root@ls-Cwj2oH9C idea]# curl localhost:49163
{"timestamp":"2022-07-17T04:04:03.880+00:00","status":404,"error":"Not Found","path":"/"}
[root@ls-Cwj2oH9C idea]# curl localhost:49163/hello


以后我们使用了Docker之后,给别人交付的就是一个镜像即可!


到了这里我们已经完全够用了Docker!

相关实践学习
通过容器镜像仓库与容器服务快速部署spring-hello应用
本教程主要讲述如何将本地Java代码程序上传并在云端以容器化的构建、传输和运行。
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。 &nbsp; &nbsp; 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
4月前
|
搜索推荐 Linux 开发工具
【docker】二进制方式安装 Docker
【docker】二进制方式安装 Docker
615 2
|
10月前
|
NoSQL 应用服务中间件 nginx
【Docker 系列】docker 学习 四,镜像相关原理
【Docker 系列】docker 学习 四,镜像相关原理
|
消息中间件 Ubuntu JavaScript
【Docker】初识Dcoker以及镜像操作(一)(上)
【Docker】初识Dcoker以及镜像操作(一)
109 1
|
NoSQL 关系型数据库 MySQL
【Docker】初识Dcoker以及镜像操作(一)(下)
【Docker】初识Dcoker以及镜像操作(一)(下)
115 0
|
Kubernetes 监控 Linux
K8S与docker的区别?
K8S与docker的区别?
|
存储 Ubuntu 数据可视化
|
运维 NoSQL Java
|
Kubernetes 监控 Linux
k8s和docker区别
k8s和docker区别
143 0
k8s和docker区别
|
Kubernetes Linux 虚拟化
k8s和docker区别2
k8s和docker区别
106 0
|
Ubuntu 应用服务中间件 Linux
Docker 镜像基本操作[Docker 系列-4](一)
镜像也是 docker 的核心组件之一,镜像时容器运行的基础,容器是镜像运行后的形态。前面我们介绍了容器的用法,今天来和大家聊聊镜像的问题。 本文是本系列的第四篇,阅读前面文章有助于更好的理解本文:
Docker 镜像基本操作[Docker 系列-4](一)