基于openEuler22.03 LTS环境的docker容器基础

一、说明

本文配置环境为VMware虚拟机或华为云服务器(4核CPU,8 GB内存,40GB磁盘),OS为openEuler 22.03 LTS ,Linux服务器要求能联网。

二、安装docker

2.1 安装docker软件包

[root@node01 ~]# dnf -y install docker

2.2 查看docker版本

[root@node01 ~]# docker version
Client:
 Version:           18.09.0
 EulerVersion:      18.09.0.323
 API version:       1.39
 Go version:        go1.17.3
 Git commit:        172f8da
 Built:             Wed Apr 19 02:01:22 2023
 OS/Arch:           linux/amd64
 Experimental:      false

Server:
 Engine:
  Version:          18.09.0
  EulerVersion:     18.09.0.323
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.17.3
  Git commit:       172f8da
  Built:            Wed Apr 19 02:00:48 2023
  OS/Arch:          linux/amd64
  Experimental:     false

2.3 启动并设置为开机自启动

[root@node01 ~]# systemctl start docker
[root@node01 ~]# systemctl enable docker

2.4 验证是否安装成功

可通过运行hello-world镜像来验证是否正确安装了Docker。

[root@node01 ~]# docker pull hello-world
Using default tag: latest
latest: Pulling from library/hello-world
c1ec31eb5944: Pull complete 
Digest: sha256:d000bc569937abbe195e20322a0bde6b2922d805332fd6d8a68b19f524b7d21d
Status: Downloaded newer image for hello-world:latest

[root@node01 ~]# docker run hello-world

Hello from Docker!
……后续输出省略……

三、docker的基本使用

在使用Docker前需要了解以下三个概念:镜像、容器和仓库。

(1)镜像:通常是只读的,一般是一个简化的Linux操作系统加上配置好环境的软件,比如一个Nginx镜像,它可能是基于Debain系统,然后安装了Nginx,从而构建成镜像。用户可以自己制作、更新镜像。

(2)容器:镜像运行的实例就是容器,每个容器都是相互隔离的。

(3)仓库:存储镜像的地方就是仓库,也就是镜像仓库,Docker官方提供的仓库为DockerHub。

3.1 获取镜像

以使用Ubuntu基本镜像为例介绍容器的使用。

如果本地没有Ubuntu镜像,则可以使用【docker pull 镜像名】命令来载入Ubuntu镜像,示例命令如下:

[root@node01 ~]# docker pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
01007420e9b0: Pull complete 
Digest: sha256:f9d633ff6640178c2d0525017174a688e2c1aef28f0a0130b26bd5554491f0da
Status: Downloaded newer image for ubuntu:latest

3.2 创建容器

获取镜像后,就可以使用这个镜像来创建一个容器,命令格式如下:

【docker run <参数> <镜像名> --name <容器名> <命令>】

示例:以上述ubuntu镜像创建一个容器,并使用/bin/bash与容器进行命令交互:

[root@node01 ~]# docker run -it ubuntu /bin/bash
root@fdf5ded8f4f6:/# exit
exit

参数说明:

  • -i:交互式操作。
  • -t:终端。
  • ubuntu:ubuntu镜像名。
  • /bin/bash:镜像名后的是命令,这里我们希望有个交互式Shell。

如上图所示,命令成功执行后,会自动进入Ubuntu容器的bash中,并等待用户的指令。

若要退出容器,直接执行exit命令即可。

3.3 查看容器

执行【docker ps -a】命令可查看所有的容器,包括已停止运行的容器,不加选项-a则只能查看正在运行的容器,示例如下:

[root@node01 ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
fdf5ded8f4f6        ubuntu              "/bin/bash"         2 minutes ago       Exited (0) 22 seconds ago                       optimistic_dubinsky
052fe1745479        hello-world         "/hello"            10 minutes ago      Exited (0) 10 minutes ago                       nifty_payne

从输出可以看到容器的ID、所属镜像、 曾执行过的命令、创建时间、状态和容器名称等信息。

3.4 启动/停止/重启/删除容器

3.4.1 启动容器

启动容器的命令格式为【docker stop <容器ID>】,示例如下(启动上面的ubuntu容器)

# 启动指定ID的容器,ID可以只写部分
[root@node01 ~]# docker start fdf5d
fdf5d

#查看容器及其运行状态
[root@node01 ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
fdf5ded8f4f6        ubuntu              "/bin/bash"         7 minutes ago       Up 4 seconds                                    optimistic_dubinsky
052fe1745479        hello-world         "/hello"            16 minutes ago      Exited (0) 16 minutes ago                       nifty_payne

 注:上述命令中,也可以用容器名称来代替容器ID,下同

3.4.2 重启容器

重启容器的命令格式为【docker restart <容器ID>】,示例如下(重启上面的ubuntu容器)

[root@node01 ~]# docker restart fdf5d
fdf5d

3.4.3 在后台运行容器

如果希望容器在后台运行,则可以通过-d参数指定容器的运行模式,比如执行以下命令可以启动一个容器在后台运行,而不会进入容器的bash终端中。

# 启动容器,并让其在后台运行
[root@node01 ~]# docker run -itd ubuntu /bin/bash
61c32a8a15354d8c54927864c0054d3f08d2f8a170d21737838493ecaae47d53

#查看容器及其状态
[root@node01 ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
61c32a8a1535        ubuntu              "/bin/bash"         32 seconds ago      Up 32 seconds                                   upbeat_galileo
fdf5ded8f4f6        ubuntu              "/bin/bash"         13 minutes ago      Up 2 minutes                                    optimistic_dubinsky
052fe1745479        hello-world         "/hello"            21 minutes ago      Exited (0) 21 minutes ago                       nifty_payne

3.4.4 进入容器

当使用 -d 参数时,容器启动后会进入后台,用户无法与容器进行交互。若要与容器进行交互,就需要进入容器,进入容器的命令格式为:【docker exec -it <容器ID> /bin/bash】

示例,进入上述id为61c32a8a1535的容器:

# 进入指定ID的容器,可以只输入部分ID
[root@node01 ~]# docker exec -it 61c32 /bin/bash
root@61c32a8a1535:/# 
root@61c32a8a1535:/# 
root@61c32a8a1535:/# exit
exit

注:如果从后台运行的容器中退出,该容器不会停止。

3.4.5 停止容器

停止容器的命令格式为:【docker stop <容器ID>】

示例,停止上述id为61c32a8a1535的容器

# 停止指定的容器
[root@node01 ~]# docker stop 61c32a8a1535
61c32a8a1535

# 查看所有容器及其状态,已停止的容器状态为Exited
[root@node01 ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                       PORTS               NAMES
61c32a8a1535        ubuntu              "/bin/bash"         10 minutes ago      Exited (137) 5 seconds ago                       upbeat_galileo
fdf5ded8f4f6        ubuntu              "/bin/bash"         23 minutes ago      Up 12 minutes                                    optimistic_dubinsky
052fe1745479        hello-world         "/hello"            32 minutes ago      Exited (0) 31 minutes ago                        nifty_payne

3.4.6 删除容器

删除容器前需要将先停止容器,删除停止状态的容器的命令格式为:【docker rm <容器ID>】,可加-f选项强制删除容器。

# 删除指定的容器
[root@node01 ~]# docker rm  61c32
61c32

# 查看容器及其状态
[root@node01 ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
fdf5ded8f4f6        ubuntu              "/bin/bash"         26 minutes ago      Up 15 minutes                                   optimistic_dubinsky
052fe1745479        hello-world         "/hello"            34 minutes ago      Exited (0) 34 minutes ago                       nifty_payne

3.4.7 查看容器日志

当某个容器运行状态异常时,通常可通过查看该容器的日志获取异常信息,并根据异常信息进行排错。

查看容器日志的命令格式为:【docker logs  <容器ID/名称>】,可加-f选项查看实时日志。

[root@node01 ~]]# docker logs 7fd6
2024-05-03 09:02:56+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.4.0-1.el8 started.
2024-05-03 09:02:56+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2024-05-03 09:02:56+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.4.0-1.el8 started.
2024-05-03 09:02:56+00:00 [Note] [Entrypoint]: Initializing database files
……此处省略后续信息输出……

四、Docker镜像的使用

4.1 查看本地镜像列表

查看本地镜像列表的命令格式为:【docker images】

示例:列出本地主机上的镜像列表

[root@node01 ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              latest              3db8720ecbf5        13 days ago         77.9MB
hello-world         latest              d2c94e258dcb        9 months ago        13.3kB

从输出可以看到镜像仓库、标签、镜像ID、创建时间和大小等信息。

4.2 查找并获取新镜像

当本地主机上需要使用一个不存在的镜像时,Docker就会自动下载这个镜像。

如果想预先下载这个镜像,可以使用【docker pull 镜像名】命令来下载它。

示例:获取MySQL的镜像命令如下

# 查找镜像
[root@node01 ~]# docker search mysql

# 下载镜像
[root@node1 ~]# docker pull mysql
Using default tag: latest
latest: Pulling from library/mysql
81badc5f380f: Pull complete 
c490e5dd1a9d: Pull complete 
87aeb61f1478: Pull complete 
1cacbea6ceda: Pull complete 
1e72891ace67: Pull complete 
42b720363d36: Pull complete 
6b3b50f9990a: Pull complete 
3811d52cfa61: Pull complete 
05bc7a0277d8: Pull complete 
cc0abd25a274: Pull complete 
Digest: sha256:ff5ab9cdce0b4c59704b4e2a09deed5ab8467be795e0ea20228b8528f53fcf82
Status: Downloaded newer image for mysql:latest

# 查看本地镜像
[root@node01 ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              latest              3db8720ecbf5        13 days ago         77.9MB
mysql               latest              a88c3e85e887        5 weeks ago         632MB
hello-world         latest              d2c94e258dcb        9 months ago        13.3kB

下载完成后,就可以直接使用这个镜像来创建容器了。

4.3 删除镜像

删除镜像的命令格式为:【docker rmi 镜像名或镜像ID】

但需要注意的是,如果有利用该镜像创建了容器,必须先停止并删除所有基于该镜像的容器,然后才能删除该镜像。

示例:删除上述测试镜像hello-world

# 查看所有容器
[root@node01 ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                         PORTS               NAMES
fdf5ded8f4f6        ubuntu              "/bin/bash"         About an hour ago   Up 45 minutes                                      optimistic_dubinsky
052fe1745479        hello-world         "/hello"            About an hour ago   Exited (0) About an hour ago                       nifty_payne

# 删除容器基于hello-world镜像的容器
[root@node01 ~]# docker rm 052fe
052fe

# 删除hello-world镜像
[root@node01 ~]# docker rmi d2c94e258dcb
Untagged: hello-world:latest
Untagged: hello-world@sha256:d000bc569937abbe195e20322a0bde6b2922d805332fd6d8a68b19f524b7d21d
Deleted: sha256:d2c94e258dcb3c5ac2798d32e1249e42ef01cba4841c2234249495f87264ac5a
Deleted: sha256:ac28800ec8bb38d5c35b49d45a6ac4777544941199075dff8c4eb63e093aa81e

4.4 创建新镜像

Ubuntu基础镜像中没有安装vim编辑器,现以基础的Ubuntu镜像为基础,在容器中安装vim编辑器,然后将该容器创建为一个新的镜像。

4.4.1 创建一个新的ubuntu容器

[root@node01 ~]# docker run --name=myubuntu -it ubuntu /bin/bash
root@151dc0b9fc72:/# vim
bash: vim: command not found
root@151dc0b9fc72:/# 

在容器中执行vim命令,可见在Ubuntu基础镜像中并没有安装vim。

4.4.2 更新Ubuntu组件

在Ubuntu容器中执行【apt-get update】命令更新Ubuntu组件,如下所示。

root@151dc0b9fc72:/# apt-get update
Get:1 http://security.ubuntu.com/ubuntu jammy-security InRelease [110 kB]
Get:2 http://archive.ubuntu.com/ubuntu jammy InRelease [270 kB]
……省略后续输出……

4.4.3 安装Vim编辑器

在Ubuntu容器中执行【apt-get -y install vim】命令安装vim编辑器

root@151dc0b9fc72:/# apt-get -y install vim
Reading package lists... Done
Building dependency tree... Done
……省略后续输出……

4.4.4 测试Vim编辑器

在Ubuntu容器中直接执行【vim】命令测试vim编辑器是否安装成功。

若出现如下图所示的界面,则表示vim安装成功。

可输入:q并回车退出vim编辑器

4.4.5 退出容器

执行exit命令退出容器。

4.4.6 创建新镜像

创建新镜像的命令格式为:【docker commit <容器ID/名称>  新镜像名】

示例:将上述新容器创建为一个新的镜像

# 查看所有容器及其状态
[root@node01 ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
151dc0b9fc72        ubuntu              "/bin/bash"         9 minutes ago       Exited (0) 48 seconds ago                       myubuntu
fdf5ded8f4f6        ubuntu              "/bin/bash"         About an hour ago   Up About an hour                                optimistic_dubinsky

# 创建一个新镜像
[root@node01 ~]# docker commit 151dc newimg/ubuntu
sha256:54088b25420a809d35989ff90702cc2de6f765ec887f5ec2f59bbaae45f38a93

# 查看所有本地镜像
[root@node01 ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
newimg/ubuntu       latest              54088b25420a        9 seconds ago       186MB
ubuntu              latest              3db8720ecbf5        13 days ago         77.9MB
mysql               latest              a88c3e85e887        5 weeks ago         632MB

五、Docker网络

5.1 基础知识

Docker引入了容器网络模型,主要包含以下三个构件:

  • Network:可理解为一个Driver,是一个第三方网络栈,主要包含bridge、host、container以及none等多种网络模式,其中bridge最常见,也是默认模式,与VMware中的桥接原理相同,使用该模式的容器均连接到 docker0 虚拟网桥上;host模式则类似NAT模式。
  • Sandbox:定义了容器内的虚拟网卡、DNS和路由表,是Network Namespace的一种实现,是容器的内部网络栈;
  • Endpoint:端点,用于连接Sandbox和Network。

另外,Docker在创建容器时,先调用控制器创建Sandbox对象,再调用容器运行时为容器创建Network Namespace。

5.2 建立并查看容器网络

5.2.1 新建容器网络

创建容器网络的命令格式为:【docker network create <网络名称>】

示例:创建一个名为test-net的容器网络

[root@node01 ~]# docker network create test-net
d164e363b4d01e88c6d831e21d3b56d7745245c6561fb23f54b4af69e57e9426

5.2.2 查看容器网络

 查看容器网络列表的命令格式为:【docker network ls】

示例:查看当前所有容器网络

[root@node01 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
99aa55d1957b        bridge              bridge              local
c8b6bf101560        docker_default      bridge              local
d4d7c34140b5        host                host                local
e610cb80750d        none                null                local
f8a57b49dc76        test-net            bridge              local

5.2.3 查看容器网络详情

查看某个容器网络详细信息的命令格式为:【docker network inspect <容器ID/名称>】

示例:查看容器名为cloud_ptuxgk 的容器网络详情,包括其中的容器IP地址等信息。

[root@node01 cloud]# docker network inspect cloud_ptuxgk 
[
    {
        "Name": "cloud_ptuxgk",
        "Id": "509361dd9d15eb46373f0c75f737fc4ccfada6a229d704a7abe1bee22ca6f176",
        "Created": "2024-05-05T20:32:21.768179018+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.22.0.0/16",
                    "Gateway": "172.22.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": true,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "3c65d690744f0daaf7314b83d6a18fd767e9182c0f06e903fd5c18e7ba50bb1d": {
                "Name": "mytomcat1",
                "EndpointID": "c3be67e73b7d7891b0e844b7a354719ed4ca6d6f061c47fe9fcc32e9be29bd8e",
                "MacAddress": "02:42:ac:16:00:03",
                "IPv4Address": "172.22.0.3/16",
                "IPv6Address": ""
            },
            "40fbd7fe98085426273cc9c62b55b595eab7337e1451b0eb57b7b3132126a314": {
                "Name": "mynginx",
                "EndpointID": "18d8f675ee30781c734c4639fbffb33a75945b16fdf845c1209144fdb3fe741d",
                "MacAddress": "02:42:ac:16:00:02",
                "IPv4Address": "172.22.0.2/16",
                "IPv6Address": ""
            },
            "439e6c63f1b4024ea73597d0995372f88ab9303f638732848121583f89ca2336": {
                "Name": "mytomcat2",
                "EndpointID": "b69d3fc8f66129bf1ab70582be0e7a05d70972e7bc61f5da74356e7eda2b1e33",
                "MacAddress": "02:42:ac:16:00:04",
                "IPv4Address": "172.22.0.4/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {
            "com.docker.compose.network": "ptuxgk",
            "com.docker.compose.project": "cloud",
            "com.docker.compose.version": "1.22.0"
        }
    }
]

5.2.4 删除容器网络

删除一个指定的容器网络的命令格式为:【docker network rm <容器ID/名称>】

删除所有未使用的容器网络的命令格式为:【docker network prune】

示例:删除名称为test-net的容器网络

[root@node01 ~]# docker network rm test-net 
test-net

六、docker容器简单实战

下面将以部署一个简单的带有反向代理和负载均衡的多容器环境的Web应用为例实战练习docker容器的应用。

6.1 Tomcat镜像和容器

6.1.1 准备测试文件

为便于测试,这里在工作目录(/opt/cloud)中准备两个自定义的测试文件,文件内容如下:

# 创建并进入目标目录
[root@node01 ~]# mkdir /opt/cloud && cd /opt/cloud/

[root@node01 cloud]# echo "mytomcat1, port is 8888." > test1.html

[root@node01 cloud]# echo "mytomcat2, port is 9999." > test2.html

6.1.2 下载tomcat镜像并创建容器

下载Tomcat镜像,然后创建两个tomcat服务器容器,并将测试文件分别挂载到Web根目录,以便后面利用这两个服务器实现和测试负载均衡。

# 新建一个名为ptuxgk的容器网络
[root@node01 ~]# docker network create ptuxgk
a4975631f730796386daa8e01fb8dd3e3068d156f95fc6e321982188c5e64a02

# 拉取tomcat镜像
[root@node01 ~]# docker pull tomcat
……此处省略系统输出……

# 创建一个名为mytomcat1的容器
[root@node01 ~]# docker run -d -p 8888:8080 --name mytomcat1 --network ptuxgk -v /opt/cloud/test1.html:/usr/local/tomcat/webapps/ROOT/test.html tomcat
5e7c38e97208f8859ff7276aee7f6c81cc213644b332db2d3baa1b299d23d504


# 创建一个名为mytomcat2的容器
[root@node01 ~]# docker run -d -p 9999:8080 --name mytomcat2 --network ptuxgk -v /opt/cloud/test2.html:/usr/local/tomcat/webapps/ROOT/test.html tomcat
a0fc9e4adf1926acfc1a61126f966cd00ccbd3a9d461ffb1ecd31f9d0099cc7e

在上面这个命令中,通过--name 选项给容器命名,使用--network选项将容器加入到指定的容器网络。使用-p选项将外部的8888或9999端口与容器中的8080端口分别进行映射。使用-v选项将准备好的测试文件分别挂载到tomcat容器中的Web网站根目录中。

成功执行上述操作后,容器列表如下所示。

[root@node01 cloud]# docker ps -a
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS                    PORTS                    NAMES
6d7e101bc3c4        tomcat               "catalina.sh run"        6 seconds ago       Up 6 seconds              0.0.0.0:9999->8080/tcp   mytomcat2
e3c7445e1049        tomcat               "catalina.sh run"        18 seconds ago      Up 17 seconds             0.0.0.0:8888->8080/tcp   mytomcat1

6.1.3 配置宿主机防火墙

openEuler的firewalld防火墙默认采用默认拒绝策略,除默认服务外,禁止一切网络流量。因此需要配置防火墙放行容器网络流量。

# 查看容器网络及其ID
[root@node01 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
99aa55d1957b        bridge              bridge              local
c8b6bf101560        docker_default      bridge              local
d4d7c34140b5        host                host                local
e610cb80750d        none                null                local
a4975631f730        ptuxgk              bridge              local

# 放行指定网络ID的网络流量
[root@node01 ~]# firewall-cmd --permanent --zone=public --add-interface=br-a4975631f730 
success

# 重载规则,使配置立即生效
[root@node01 ~]# firewall-cmd --reload 
success

6.1.4 测试访问

启动客户机浏览器,访问【云服务器或虚拟机IP地址:8888】或【云服务器或虚拟机IP地址:9999】,可看到网站会提示404的错误,如下图所示。

出现上述错误的原因是Tomcat基础镜像中的Web站点根目录下没有内容。可通过以下方式解决:

(1)以交互式方式进入容器

# 以交互方式启动tomcat容器
[root@node01 ~]# docker exec -it mytomcat1 /bin/bash

(2)复制应用文件至网站webapps目录

# 可查看到网站目录webapps为空
root@5e7c38e97208:/usr/local/tomcat# ll webapps
total 16
drwxr-xr-x. 2 root root 4096 May  2 06:54 ./
drwxr-xr-x. 1 root root 4096 May  2 06:54 ../

# 将webapps.dist目录的文件复制到webapps中
root@5e7c38e97208:/usr/local/tomcat# cp -a webapps.dist/* webapps/

 同样的操作,配置另一个tomcat容器的网站目录。

完成上述操作后,再次访问或刷新页面,可以看到如下所示的正常示例页面。

访问虚拟机的8888端口,如下所示。 

访问虚拟机的9999端口,如下所示。 

分别测试访问测试文件如下:

6.1.5 制作镜像

为方便后面使用,可以将配置好的tomcat容器制作成一个新的镜像,并指定镜像标签为latest。

# 将mytomcat1容器创建成一个新镜像mywebsite1
[root@node01 ~]# docker commit mytomcat1 mywebsite1:latest
sha256:f0a22d536bae9a3431dadbfb6e5640e4236c8305243a3b6c3198181d92c07ef4

# 将mytomcat2容器创建成一个新镜像mywebsite2
[root@node01 ~]# docker commit mytomcat2 mywebsite2:latest
sha256:2e2d4c2b1f40be57003719a13d256c32aecf046ffa03c1e9f0218dd9f8180fba

# 查看镜像
[root@node01 ~]# docker images
REPOSITORY           TAG                 IMAGE ID            CREATED              SIZE
mywebsite2           latest              982ea35559fd        54 seconds ago       460MB
mywebsite1           latest              83c83ce3e402        About a minute ago   460MB
tomcat               latest              fca42eb4b550        3 days ago           455MB

6.2 nginx镜像与容器

Nginx是一个高性能的HTTP和反向代理服务器,下面介绍利用nginx镜像及其容器配置反向代理服务器。

6.2.1 准备nginx配置文件

在工作目录/opt/cloud下事先准备好Nginx服务器的配置文件nginx.conf文件,文件内容如下。

# 创建nginx.conf文件,并在其中添加如下内容
[root@node01 cloud]# vim nginx.conf
# 添加以下内容
user nginx;
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    #配置负载均衡,upstream后面的标识符可自定义,要求与后面的反向代理主机名一致
    upstream www.mywebsite.com {        
        server mytomcat1:8080 weight=1;    #mytomcat1和mytomcat2为前面创建的容器名称
        server mytomcat2:8080 weight=1;
    }
    server {
        listen       80;
        server_name  localhost;
        location / {
           #配置反向代理,所有对/下的请求均代理至主机www.mywebsite.com
           proxy_pass http://www.mywebsite.com;    
           #请求头设置,防止出现跨域问题,本项目中,以下4行内容可有可无
           proxy_set_header Host $http_host;
           proxy_set_header X-Real-IP $remote_addr;
           proxy_set_header REMOTE-HOST $remote_addr;
           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
	}
}

注:在该配置文件中,负载均衡策略采用轮询策略,由upstream模块提供该功能。每个请求会按时间平均分配到不同的后端Web服务器。

后端Web服务器server的配置格式为: server 服务器IP或名称:端口 weight=n;

此处服务器名称指定为前面创建的tomcat容器名称,端口为容器内部监听的端口号,weight表示轮询的几率,这里统一配置成1,表示两个服务器轮询几率相同。

6.2.2 下载nginx镜像并创建nginx容器

下载nginx镜像,并利用该镜像创建nginx容器,并将示例目录/opt/cloud下的nginx.conf文件挂载到容器中的/etc/nginx/nginx.conf。

# 拉取nginx镜像
[root@node01 cloud]# docker pull nginx
Using default tag: latest
……此处省略其它系统输出……

# 创建一个名为mynginx的容器
[root@node01 cloud]# docker run -d --name mynginx --network ptuxgk -p 80:80 -v /opt/cloud/nginx.conf:/etc/nginx/nginx.conf nginx
c90b0f9a478889eb4c5eb667d6beab66765919d2aec57c320f19e592ab426ef1

与tomcat容器一样,这里也给容器命名为mynginx,并加入到网络ptuxgk中,同时将内部的80端口映射到外部的80端口。

成功完成上述操作后,容器列表如下所示。

[root@node01 cloud]# docker ps -a
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS                    PORTS                    NAMES
a47bf7c55309        nginx                "/docker-entrypoint.…"   38 seconds ago      Up 37 seconds             0.0.0.0:80->80/tcp       mynginx
6d7e101bc3c4        tomcat               "catalina.sh run"        21 minutes ago      Up 21 minutes             0.0.0.0:9999->8080/tcp   mytomcat2
e3c7445e1049        tomcat               "catalina.sh run"        21 minutes ago      Up 21 minutes             0.0.0.0:8888->8080/tcp   mytomcat1

6.2.3 配置防火墙

到此步如果直接访问虚拟机IP地址的80端口和测试文件,会提示如下图所示的404错误。

查看容器mynginx的日志可以看到如下错误提示。

[root@node01 ~]# docker logs mynginx 
……此处省略其它日志输出……
2024/05/05 11:20:22 [error] 28#28: *38 no live upstreams while connecting to upstream, client: 192.168.17.1, server: localhost, request: "GET /test.html HTTP/1.1", upstream: "http://www.mywebsite.com/test.html", host: "192.168.17.218"

 出现该错误提示可能是防火墙拉截导致的,在宿主机中,配置如下防火墙规则。

# 放行指定8888和9999的TCP端口流量
[root@node01 ~]# firewall-cmd --permanent --zone=public --add-port={8888,9999}/tcp
success

# 重载规则,使配置立即生效
[root@node01 ~]# firewall-cmd --reload 
success

6.2.4 测试访问

刷新页面,或者再次访问,可正常访问,如下所示。

刷新页面,可看到另一个测试文件内容,如下所示。

 

反复刷新,可以看到页面内容不断切换,证明负载均衡服务工作正常。 

七、利用docker-compose一键部署网站

很明显,上面连通多个容器的方式很不方便,每次新建或者删除容器都需要很多步骤。

下面将介绍docker-compose,并通过docker-compose一键高效部署和运行网站。

7.1 安装docker-compose

首先需要安装Docker Compose

# 安装docker-compose
[root@node1 ~]# dnf -y install docker-compose

# 查看docker-compose的版本
[root@node1 ~]# docker-compose --version
docker-compose version 1.22.0, build f46880f

7.2 创建docker-compose配置文件

在前面创建的工作目录中创建一个名为docker-compose.yml的脚本文件,这是Docker Compose默认会读取的配置文件:

# 进入工作目录
[root@node1 ~]# cd /opt/cloud/

# 创建docker-compose.yml配置文件
[root@node1 cloud]# vim docker-compose.yml
# 文件内容如下

---
version: '3'
services:
  mywebserver1:
    image: mywebsite1
    container_name: mytomcat1
    volumes:
      - "/opt/cloud/test1.html:/usr/local/tomcat/webapps/ROOT/test.html"
    ports:
      - "8888:8080"
    networks:
      - ptuxgk
  mywebserver2:      
    image: mywebsite2
    container_name: mytomcat2
    volumes:
      - "/opt/cloud/test2.html:/usr/local/tomcat/webapps/ROOT/test.html"	
    ports:
      - "9999:8080" 
    networks:
      - ptuxgk      
  webproxy:
    image: nginx
    container_name: mynginx
    volumes:
      - "/opt/cloud/nginx.conf:/etc/nginx/nginx.conf"
    ports:
      - "80:80"
    networks:
      - ptuxgk
networks:
    ptuxgk:

这里与docker命令相似,同样指定了容器的名称(container_name),容器的镜像(image),挂载的文件或目录(volumes)以及开放的端口(ports),以及利用networks关键词声明一个名为ptuxgk的网络,并将各容器加入到该网络中。

注:上述yaml文件严格要求上下对齐,比如mywebserver1与webproxy必须左对齐,且前面不能用Tab键对齐,只能用空格,且每行后面不能有多余的空格,否则都会提示语法错误。

7.3 停止并删除容器

为排除干扰,停止并删除前面已创建和启动的容器。

# 查看所有容器
[root@node01 ~]# docker ps -a

# 停止正在运行的容器
[root@node01 ~]# docker stop mytomcat1
[root@node01 ~]# docker stop mytomcat2
[root@node01 ~]# docker stop mynginx

# 删除所有基于tomcat和nginx镜像的容器
[root@node01 ~]# docker rm mytomcat1
[root@node01 ~]# docker rm mytomcat2
[root@node01 ~]# docker rm mynginx

7.4 一键部署

进入docker-compose.yml文件所在的目录,执行【docker-compose up -d】命令启动应用程序。
这里的参数-d表示后台运行。

[root@node01 cloud]# docker-compose up -d
Creating network "cloud_ptuxgk" with the default driver
Creating mytomcat1 ... done
Creating mynginx   ... done
Creating mytomcat2 ... done

注:从上面的输出可以看出创建的容器网络名为cloud_ptuxgk,这里的cloud其实是当前目录的名称。

查看容器状态,可以看到三个容器已成功运行。

[root@node01 cloud]# docker ps -a
CONTAINER ID        IMAGE                COMMAND                  CREATED              STATUS                    PORTS                    NAMES
439e6c63f1b4        mywebsite2           "catalina.sh run"        About a minute ago   Up About a minute         0.0.0.0:9999->8080/tcp   mytomcat2
3c65d690744f        mywebsite1           "catalina.sh run"        About a minute ago   Up About a minute         0.0.0.0:8888->8080/tcp   mytomcat1
40fbd7fe9808        nginx                "/docker-entrypoint.…"   About a minute ago   Up About a minute         0.0.0.0:80->80/tcp       mynginx

7.5 配置防火墙

因自动创建的容器网络与前面手动创建的容器网络并非同一个,因此这里还需要配置防火墙,放行自动创建的容器网络流量。

(1)查看容器网络ID

[root@node01 cloud]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
99aa55d1957b        bridge              bridge              local
509361dd9d15        cloud_ptuxgk        bridge              local    #自动创建的容器网络
c8b6bf101560        docker_default      bridge              local
d4d7c34140b5        host                host                local
e610cb80750d        none                null                local
a4975631f730        ptuxgk              bridge              local

 (2)配置防火墙

[root@node01 cloud]# firewall-cmd --permanent --zone=public --add-interface=br-509361dd9d15 
success

[root@node01 cloud]# firewall-cmd --reload 
success

7.6 测试访问

打开浏览器,访问宿主机IP地址的80端口,可以看到正确的网页内容。

刷新页面,成功切换

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/594043.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

电机控制系列模块解析(15)—— 母线小电容

一、薄膜电容 在家电产品和工业变频器中&#xff0c;使用容值更小但耐压更高的薄膜电容来代替传统的电解电容作为逆变器母线电容&#xff0c;这种技术趋势已经得到了广泛应用和产品化。以下是关于这一替换技术的一些关键考量和优势&#xff1a; 长期稳定性与可靠性&#xff1a…

3-qt综合实例-贪吃蛇的游戏程序

引言&#xff1a; 如题&#xff0c;本次实践课程主要讲解贪吃蛇游戏程序。 qt贪吃蛇项目内容&#xff1a; 一、功能需求 二、界面设计 各组件使用&#xff1a; 对象名 类 说明 Widget QWidge 主窗体 btnRank QPushButton 排行榜-按钮 groupBox QGroupBox 难…

牛客NC383 主持人调度(一)【简单 排序 Java/Go/C++】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/e160b104354649b69600803184094adb 思路 直接看代码&#xff0c;不难Java代码 import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返…

CMakeLists.txt语法规则:控制编译的变量

一. 简介 前面一篇文章学习了 CMakeLists.txt语法中的 部分常量变量&#xff0c;具体学习提供信息的变量。 本文继续学习 CMakeLists.txt语法中&#xff1a;控制编译的变量。 二. CMakeLists.txt语法规则&#xff1a;控制编译的变量 这些变量可以控制编译过程&#xff0c;…

[C语言]指针进阶详解

指针是C语言的精髓所以内容可能会比较多&#xff0c;需要我们认真学习 目录 1、字符指针 2、指针数组 3、数组指针 3.1数组指针的定义 3.2&数组名vs数组名 3.3数组指针的使用 4、数组传参和指针传参 4.1一维数组传参 4.2二维数组传参 4.3一级指针传参 4.4二级指…

【Docker学习】docker run的端口映射-p和-P选项

docker run的端口映射选项分为-p&#xff08;小写&#xff0c;全称--publish&#xff09;&#xff0c;-P&#xff08;大写&#xff0c;全称--publish-all&#xff09;&#xff0c;之前认为只有改变容器发布给宿主机的默认端口号才会进行-p的设置&#xff0c;而不改变默认端口号…

现代信号处理8_递归的最小二乘(CSDN_20240505)

递归的最小二乘大约出现在50年前。递归&#xff0c;就是在已经算出的结果的基础下&#xff0c;当新的数据到来时&#xff0c;不需要再对数据进行一次完整的运算&#xff0c;而是在已有结果的基础上做一些简单的调整&#xff0c;就能得到新的结果。使用递归的好处&#xff1a; …

面试中算法(使用栈实现队列)

使用栈来模拟一个队列&#xff0c;要求实现队列的两个基本操作:入队、出队。 栈的特点&#xff1a;先入后出&#xff0c;出入元素都是在同一端&#xff08;栈顶&#xff09;。 队列的特点&#xff1a;先入先出&#xff0c;出入元素是在两端&#xff08;队头和队尾)。 分析&…

ICode国际青少年编程竞赛- Python-1级训练场-for循环与变量

ICode国际青少年编程竞赛- Python-1级训练场-for循环与变量 1、 a 1 for i in range(4):Spaceship.step(a)Dev.step(2)Dev.step(-2)a a 12、 a 1 for i in range(4):Spaceship.step(a)Dev.step(3)Dev.step(-3)a a 13、 a 1 for i in range(4):Dev.turnLeft()Dev.step(…

【机器学习】Ctrl-Adapter:视频生成领域的革新者

Ctrl-Adapter&#xff1a;视频生成领域的革新者 一、ControlNets的挑战与Ctrl-Adapter的应运而生二、Ctrl-Adapter的技术原理与实现三、Ctrl-Adapter的应用实例与性能表现四、Ctrl-Adapter的意义与未来展望 随着人工智能技术的飞速发展&#xff0c;图像与视频生成领域正经历着前…

【电源专题】拿人体的循环系统与板级电源做个比较

一般人可能会觉得电源大概是电子设备里面比较容易搞定的门类。因为,只要线路没有接错,指示灯(如果有)能亮,电源都能工作。从这个方面说,好像是很容易。但是通过多年的经验和经历的坑,发现电源其实是一个很麻烦的东西,稍微有一点不完美就会有大问题出现。 如果将人体也当…

基于Springboot的水产养殖系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的水产养殖系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&…

ue引擎游戏开发笔记(30)——对角色移动进行优化:实现人物转向

1.需求分析&#xff1a; 当前我们只实现了通过控制器可使角色进行前后左右的移动&#xff0c;但角色移动时与动画不匹配&#xff0c;并不会进行转向&#xff0c;实现角色随移动转向。 2.操作实现&#xff1a; 1思路&#xff1a;利用反转换函数inverse transform direction获取…

GitHub Desktop安装与使用教程

GitHub Desktop 是GitHub公司推出的一款桌面应用程序&#xff0c;旨在帮助开发人员更轻松使用GitHub。它提供了一个直观的用户界面&#xff0c;允许用户通过图形化界面来执行常见的 Git 操作&#xff0c;如克隆仓库、创建分支、提交更改、合并代码等。 GitHub Desktop 的设计使…

mac自定义快捷键打开系统应用

最终效果是达成altg直接打开浏览器&#xff0c;解放双手、再也不需要移动鼠标双击打开应用啦&#xff01;&#xff01;&#xff01;&#xff5e; 1.commandspace输入自动操作 2.选择快速操作 3.选择使用工具、运行appleScrpit 4.输入打开浏览器代码 tell application "G…

Day31:单元测试、项目监控、项目部署、项目总结、常见面试题

单元测试 保证独立性。 Assert&#xff1a;断言&#xff0c;一般用来比较是否相等&#xff0c;比如 Assert.assertEquals 在JUnit测试框架中&#xff0c;BeforeClass&#xff0c;Before&#xff0c;After和AfterClass是四个常用的注解&#xff0c;它们的作用如下&#xff1a; …

FFmpeg学习记录(四)——SDL音视频渲染实战

1.SDL使用的基本步骤 SDL Init/sDL _Quit()SDL_CreateWindow()/SDL_DestoryWindow()SDL CreateRender() SDL_Windows *windows NULL;SDL_Init(SDL_INIT_VIDEO);window SDL_CreateWindow("SDL2 Windows",200,200, 640,480,SDL_WINDOW_SHOWN);if(!window) {printf(&…

手撕netty源码(四)- ServerBootstrap是如何监听事件的

文章目录 前言一、OP_ACCEPT事件注册1.1 bind 完成之后监听OP_ACCEPT1.2 register0注册完成之后监听OP_ACCEPT 二、事件处理在这里插入图片描述 三、总结 前言 文档中的图片如果不清晰可以直接在线看processOn processOn文档跳转 接上一篇&#xff1a;手撕netty源码&#xff0…

基于Springboot的校园疫情防控系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的校园疫情防控系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构…

力扣每日一题112:路径总和

题目 简单 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径&#xff0c;这条路径上所有节点值相加等于目标和 targetSum 。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 叶子节点 是…
最新文章