# 2.OpenFaaS安装部署和使用

## OpenFasS安装部署和使用

## （一）开始前的准备

* 克隆虚拟机，并配置好静态IP
* 配置两台虚拟机的代理

以下详述。

### 1. 克隆一台虚拟机

为了演示集群，在上一篇记录最后的状态上，克隆一台虚拟机。

![](/files/-Lg5jP6WmHW5A3p004Xi)

并修改其静态IP为：`192.168.237.129`。详细修改见上一篇安装CentOS。

![](/files/-Lg5jP6YTfGM_J05q8E1)

修改`/etc/sysconfig/network-scripts/ifcfg-ens33`后需要重启网络服务

```
# service network restart
```

### 2. 配置代理（可选）

由于有一些翻墙下载，需要配置代理服务器下载。通过命令行配置，从简。

必要的说明：宿主机`192.168.237.1`已有的代理端口`2333`

配置如下。

```
export http_proxy=http://192.168.237.1:2333
export https_proxy=http://192.168.237.1:2333
```

据后来测试，`curl`代理下载仍然慢，还影响`yum`源安装时的选择，需要取消代理。关于需要翻墙的下载，还行下载后拷贝过来。

```
export http_proxy=
export https_proxy=
```

## （二）安装部署

参考官网

### 1.[基于Docker Swarm部署](https://docs.openfaas.com/deployment/docker-swarm/)

#### 1.1Docker Swarm [补充学习](https://docs.docker.com/engine/swarm/swarm-tutorial/)

按上面的步骤，克隆出第三台虚拟机，并配置好静态IP：`192.168.237.130`

修改主机名 `/etc/hostname`

| manager1        | worker1         | worker2         |
| --------------- | --------------- | --------------- |
| 192.168.237.128 | 192.168.237.129 | 192.168.237.130 |

说明：打开主机之间的协议和端口。必须提供以下端口。在某些系统上，默认情况下这些端口是打开的。

* 用于集群管理通信的 **TCP端口2377**
* **TCP** 和 **UDP端口7946** 用于节点之间的通信
* **UDP端口4789** 用于覆盖网络流量

如果您计划使用encryption（`--opt encrypted`）创建覆盖网络，则还需要确保允许**ip protocol 50**（**ESP**）流量。

可以用命令`telnet 192.168.237.128 2377`测试

```
[root@worker1 ~]# telnet 192.168.237.128 2377
Trying 192.168.237.128...
telnet: connect to address 192.168.237.128: No route to host
```

对于CentOS要开启防火墙

打开端口（貌似这个才最常用）

查看所有打开的端口：

**# firewall-cmd --zone=dmz --list-ports**

加入一个端口到区域：

**# firewall-cmd --zone=dmz --add-port=8080/tcp**

永久生效再加上 **--permanent** 然后reload防火墙

更新防火墙规则：

**# firewall-cmd --reload**

打开所有测试需要的端口

```
# firewall-cmd --zone=dmz --add-port=2377/tcp --add-port=7946/tcp --add-port=7946/udp --add-port=4789/udp --permanent
# firewall-cmd --reload
```

经测试还是无效。

关闭防火墙

```
systemctl disable firewalld && systemctl stop firewalld
```

经测试有效，果然是防火墙的问题，但为啥防火墙规则配置无效，不明。

准备结束。

在`manager1`上运行如下命令，新建一个`swarm`

```
[root@manager1 ~]# docker swarm init --advertise-addr 192.168.237.128
Swarm initialized: current node (qfge07btc9daqarfrwm6q0hy7) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join \
    --token SWMTKN-1-2u8nmafs0zun1w6fxfpo06s1lpj53nzo5ugnqi0k7l00makawo-axiiswn6c1iciieul9eysw08v \
    192.168.237.128:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
```

`--advertise-addr`标志配置管理器节点以将其地址发布为`192.168.99.100`。群中的其他节点必须能够访问IP地址处的管理器。

输出内容包括将新节点连接到群集的命令。节点将作为管理者或工作者加入，具体取决于`--token`标志的值。

然后运行`docker info`可以查看Swarm状态

```
Swarm: active
 NodeID: qfge07btc9daqarfrwm6q0hy7
 Is Manager: true
 ClusterID: 914p9w26eztw122j30cetlvsx
 Managers: 1
 Nodes: 1
 Orchestration:
  Task History Retention Limit: 5
 Raft:
  Snapshot Interval: 10000
  Number of Old Snapshots to Retain: 0
  Heartbeat Tick: 1
  Election Tick: 3
 Dispatcher:
  Heartbeat Period: 5 seconds
 CA Configuration:
  Expiry Duration: 3 months
 Node Address: 192.168.237.128
 Manager Addresses:
  192.168.237.128:2377
```

运行`docker node ls`可以查看节点信息

```
[root@manager1 ~]# docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
qfge07btc9daqarfrwm6q0hy7 *   manager1            Ready               Active              Leader
```

在`*`旁边的节点ID表明当前连接此节点上。

在worker1和worker2上加入

```
[root@worker2 ~]# docker swarm join \
>     --token SWMTKN-1-2u8nmafs0zun1w6fxfpo06s1lpj53nzo5ugnqi0k7l00makawo-axiiswn6c1iciieul9eysw08v \
>     192.168.237.128:2377
This node joined a swarm as a worker.
```

```
[root@worker1 ~]# docker swarm join \
>     --token SWMTKN-1-2u8nmafs0zun1w6fxfpo06s1lpj53nzo5ugnqi0k7l00makawo-axiiswn6c1iciieul9eysw08v \
>     192.168.237.128:2377
This node joined a swarm as a worker.
```

现在在`manager1`上查看信息

```
[root@manager1 ~]# docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
164tibjpsoq80to1ktc4rp5ej     worker2             Ready               Active              
qfge07btc9daqarfrwm6q0hy7 *   manager1            Ready               Active              Leader
sr304jpfeprorr77olhqgqkkp     worker1             Ready               Active
```

在工作节点上没有查看节点信息的权限

```
[root@worker1 ~]# docker node ls
Error response from daemon: This node is not a swarm manager. Worker nodes can't be used to view or modify cluster state. Please run this command on a manager node or promote the current node to a manager.
```

在manager1节点上创建服务`docker service create --replicas 1 --name helloworld alpine ping docker.com`

```
[root@manager1 ~]# docker service create --replicas 1 --name helloworld alpine ping docker.com
1d5qs34fqw885n4uy47xo93x0
Since --detach=false was not specified, tasks will be created in the background.
In a future release, --detach=false will become the default.
```

其中，

* `docker service create`命令创建服务。
* `--name`标志命名该服​​务`helloworld`
* `--replicas`标志指定1个正在运行的实例的所需状态。
* 参数`alpine ping docker.com`将服务定义为执行命令的Alpine Linux容器`ping docker.com`

运行`docker service ls`以查看正在运行的服务列表：

```
[root@manager1 ~]# docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
1d5qs34fqw88        helloworld          replicated          1/1                 alpine:latest
```

运行`docker service inspect --pretty <SERVICE-ID>`以易于阅读的格式显示有关服务的详细信息。

要查看有关`helloworld`服务的详细信息：

```
[root@manager1 ~]# docker service inspect --pretty helloworld

ID:        1d5qs34fqw885n4uy47xo93x0
Name:        helloworld
Service Mode:    Replicated
 Replicas:    1
Placement:
UpdateConfig:
 Parallelism:    1
 On failure:    pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Update order:      stop-first
RollbackConfig:
 Parallelism:    1
 On failure:    pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Rollback order:    stop-first
ContainerSpec:
 Image:        alpine:latest@sha256:7043076348bf5040220df6ad703798fd8593a0918d06d3ce30c6c93be117e430
 Args:        ping docker.com 
Resources:
Endpoint Mode:    vip
```

要以json格式返回服务详细信息，请运行不带`--pretty`标志的相同命令。

```
[root@manager1 ~]# docker service inspect helloworld
[
    {
        "ID": "1d5qs34fqw885n4uy47xo93x0",
        "Version": {
            "Index": 20
        },
        "CreatedAt": "2018-08-02T10:31:23.706370975Z",
        "UpdatedAt": "2018-08-02T10:31:23.706370975Z",
        "Spec": {
            "Name": "helloworld",
            "Labels": {},
            "TaskTemplate": {
                "ContainerSpec": {
                    "Image": "alpine:latest@sha256:7043076348bf5040220df6ad703798fd8593a0918d06d3ce30c6c93be117e430",
                    "Args": [
                        "ping",
                        "docker.com"
                    ],
                    "StopGracePeriod": 10000000000,
                    "DNSConfig": {}
                },
                "Resources": {
                    "Limits": {},
                    "Reservations": {}
                },
                "RestartPolicy": {
                    "Condition": "any",
                    "Delay": 5000000000,
                    "MaxAttempts": 0
                },
                "Placement": {},
                "ForceUpdate": 0
            },
            "Mode": {
                "Replicated": {
                    "Replicas": 1
                }
            },
            "UpdateConfig": {
                "Parallelism": 1,
                "FailureAction": "pause",
                "Monitor": 5000000000,
                "MaxFailureRatio": 0,
                "Order": "stop-first"
            },
            "RollbackConfig": {
                "Parallelism": 1,
                "FailureAction": "pause",
                "Monitor": 5000000000,
                "MaxFailureRatio": 0,
                "Order": "stop-first"
            },
            "EndpointSpec": {
                "Mode": "vip"
            }
        },
        "Endpoint": {
            "Spec": {}
        }
    }
]
```

运行`docker service ps <SERVICE-ID>`

以查看正在运行服务的节点：

```
[root@manager1 ~]# docker service ps helloworld
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE            ERROR                       PORTS
c3tin0odi0si        helloworld.1        alpine:latest       worker1             Running             Running 11 minutes ago                               
mwxqhw1n6na4         \_ helloworld.1    alpine:latest       manager1            Shutdown            Failed 11 minutes ago    "task: non-zero exit (1)"   
j2stxm2vvaz2         \_ helloworld.1    alpine:latest       manager1            Shutdown            Failed 12 minutes ago    "task: non-zero exit (1)"   
yolm4hgnoand         \_ helloworld.1    alpine:latest       manager1            Shutdown            Failed 12 minutes ago    "task: non-zero exit (1)"   
tado3i2ti0mz         \_ helloworld.1    alpine:latest       manager1            Shutdown            Failed 12 minutes ago    "task: non-zero exit (1)"
```

在这种情况下，服务的一个实例`helloworld`正在`worker1`节点上运行。也可能会在管理器节点上运行。

默认情况下，swarm中的管理器节点可以像工作节点一样执行任务。

在运行任务的节点上运行`docker ps`，以查看有关该任务的容器的详细信息。

```
[root@worker1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
7acea91a6a8a        alpine:latest       "ping docker.com"   15 minutes ago      Up 15 minutes                           helloworld.1.c3tin0odi0sivv7rf1kzixbh8
```

**提示**：如果`helloworld`正在管理器节点以外的节点上运行，则必须ssh到该节点。

运行以下命令以更改在swarm中运行的服务的所需状态：docker service scale \<SERVICE-ID>=\<NUMBER-OF-TASKS>

```
[root@manager1 ~]# docker service scale helloworld=5
helloworld scaled to 5
```

运行`docker service ps <SERVICE-ID>`以查看更新的任务列表：

```
[root@manager1 ~]# docker service ps helloworld
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE                ERROR                       PORTS
c3tin0odi0si        helloworld.1        alpine:latest       worker1             Running             Running 18 minutes ago                                   
mwxqhw1n6na4         \_ helloworld.1    alpine:latest       manager1            Shutdown            Failed 18 minutes ago        "task: non-zero exit (1)"   
j2stxm2vvaz2         \_ helloworld.1    alpine:latest       manager1            Shutdown            Failed 19 minutes ago        "task: non-zero exit (1)"   
yolm4hgnoand         \_ helloworld.1    alpine:latest       manager1            Shutdown            Failed 19 minutes ago        "task: non-zero exit (1)"   
tado3i2ti0mz         \_ helloworld.1    alpine:latest       manager1            Shutdown            Failed 19 minutes ago        "task: non-zero exit (1)"   
baj5429fptoq        helloworld.2        alpine:latest       worker1             Running             Running 20 seconds ago                                   
9v1uzjbqu5k2         \_ helloworld.2    alpine:latest       manager1            Shutdown            Failed 26 seconds ago        "task: non-zero exit (1)"   
iu6xmkojng6w         \_ helloworld.2    alpine:latest       worker2             Shutdown            Failed 36 seconds ago        "task: non-zero exit (1)"   
upo12ke12z58         \_ helloworld.2    alpine:latest       worker2             Shutdown            Failed 47 seconds ago        "task: non-zero exit (1)"   
80un6zvuw7q9        helloworld.3        alpine:latest       worker1             Running             Running 20 seconds ago                                   
sn5gx3opagqr         \_ helloworld.3    alpine:latest       worker2             Shutdown            Failed 25 seconds ago        "task: non-zero exit (1)"   
0iv09zlttz5c         \_ helloworld.3    alpine:latest       worker2             Shutdown            Failed 36 seconds ago        "task: non-zero exit (1)"   
s1cidjv5ycjl         \_ helloworld.3    alpine:latest       worker2             Shutdown            Failed 47 seconds ago        "task: non-zero exit (1)"   
pxv0vcr0yicb        helloworld.4        alpine:latest       worker1             Running             Running about a minute ago                               
y6lafc2d8lid        helloworld.5        alpine:latest       worker1             Running             Running 11 seconds ago                                   
nplgwq5cyu40         \_ helloworld.5    alpine:latest       worker2             Shutdown            Failed 16 seconds ago        "task: non-zero exit (1)"   
9lua203a11se         \_ helloworld.5    alpine:latest       manager1            Shutdown            Failed 26 seconds ago        "task: non-zero exit (1)"   
330jk7ut93ze         \_ helloworld.5    alpine:latest       manager1            Shutdown            Failed 37 seconds ago        "task: non-zero exit (1)"   
igptfi644btq         \_ helloworld.5    alpine:latest       manager1            Shutdown            Failed 47 seconds ago        "task: non-zero exit (1)"
```

您可以看到swarm创建了4个新任务，可以扩展到总共5个运行的Alpine Linux实例。任务分布在群的三个节点之间。

运行`docker service rm helloworld`以删除该`helloworld`服务。

```
[root@manager1 ~]# docker service rm helloworld
helloworld
```

运行`docker service inspect <SERVICE-ID>`以验证群集管理器是否已删除该服务。CLI返回未找到服务的消息：

```
[root@manager1 ~]# docker service inspect helloworld
[]
Status: Error: no such service: helloworld, Code: 1
```

即使服务不再存在，任务容器也需要几秒钟来清理。您可以在节点上使用`docker ps`以验证何时删除了任务。

将Redis 3.0.6部署到swarm并使用10秒更新延迟配置swarm：

```
[root@manager1 ~]# docker service create \
>   --replicas 3 \
>   --name redis \
>   --update-delay 10s \
>   redis:3.0.6

36yu81hd03hl5amuy3wi8neax
Since --detach=false was not specified, tasks will be created in the background.
In a future release, --detach=false will become the default.
```

可以在服务部署时配置滚动更新策略。

`--update-delay`标志配置服务任务或任务集的更新之间的时间延迟。可以将时间`T`描述为秒数`s`，分钟数`m`或小时数的组合`h`。所以`10m30s`表示延迟10分30秒。

默认情况下，调度程序一次更新1个任务。您可以传递该`--update-parallelism`标志以配置调度程序同时更新的最大服务任务数。

默认情况下，当对单个任务的更新返回状态时`RUNNING`，调度程序会安排另一个任务进行更新，直到所有任务都更新为止。如果在更新任务期间的任何时间返回`FAILED`，则调度程序会暂停更新。可以使用`--update-failure-action`标志或来控制行为。

检查`redis`服务：

```
[root@manager1 ~]# docker service inspect --pretty redis

ID:        36yu81hd03hl5amuy3wi8neax
Name:        redis
Service Mode:    Replicated
 Replicas:    3
Placement:
UpdateConfig:
 Parallelism:    1
 Delay:        10s
 On failure:    pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Update order:      stop-first
RollbackConfig:
 Parallelism:    1
 On failure:    pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Rollback order:    stop-first
ContainerSpec:
 Image:        redis:3.0.6@sha256:6a692a76c2081888b589e26e6ec835743119fe453d67ecf03df7de5b73d69842
Resources:
Endpoint Mode:    vip
```

现在可以更新容器镜像`redis`。swarm管理器根据`UpdateConfig`策略将更新应用于节点：

```
[root@manager1 ~]# docker service update --image redis:3.0.7 redis
redis
Since --detach=false was not specified, tasks will be updated in the background.
In a future release, --detach=false will become the default.
```

调度程序默认情况下应用滚动更新，如下所示：

* 停止第一个任务。
* 安排已停止任务的更新。
* 启动容器以获取更新的任务。
* 如果对任务的更新返回`RUNNING`，请等待指定的延迟时间，然后开始下一个任务。
* 如果在更新期间的任何时间返回任务`FAILED`，请暂停更新。

运行`docker service inspect --pretty redis`以查看所需状态的新图像：

```
[root@manager1 ~]# docker service inspect --pretty redis

ID:        36yu81hd03hl5amuy3wi8neax
Name:        redis
Service Mode:    Replicated
 Replicas:    3
UpdateStatus:
 State:        updating
 Started:    About a minute
 Message:    update in progress
Placement:
UpdateConfig:
 Parallelism:    1
 Delay:        10s
 On failure:    pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Update order:      stop-first
RollbackConfig:
 Parallelism:    1
 On failure:    pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Rollback order:    stop-first
ContainerSpec:
 Image:        redis:3.0.7@sha256:730b765df9fe96af414da64a2b67f3a5f70b8fd13a31e5096fee4807ed802e20
Resources:
Endpoint Mode:    vip
```

重新启动暂停的更新运行`docker service update <SERVICE-ID>`。例如：

```
[root@manager1 ~]# docker service update redis
redis
Since --detach=false was not specified, tasks will be updated in the background.
In a future release, --detach=false will become the default.
```

为避免重复某些更新失败，您可能需要通过传递标志来重新配置服务`docker service update`。

运行`docker service ps <SERVICE-ID>`以查看滚动更新：

```
Since --detach=false was not specified, tasks will be updated in the background.
In a future release, --detach=false will become the default.
[root@manager1 ~]# docker service ps redis
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE             ERROR               PORTS
tb3hhkawq941        redis.1             redis:3.0.6         manager1            Running             Preparing 9 minutes ago                       
uglfpty2fwvq        redis.2             redis:3.0.7         worker1             Running             Preparing 3 minutes ago                       
jfzv1prt72j7         \_ redis.2         redis:3.0.6         worker1             Shutdown            Shutdown 3 minutes ago                        
mi95dmqjrviz        redis.3             redis:3.0.6         worker2             Running             Preparing 9 minutes ago
```

在Swarm更新所有任务之前，您可以看到一些正在运行`redis:3.0.6`而另一些正在运行`redis:3.0.7`。

在本教程的早期步骤中，所有节点都在运行时具有`ACTIVE`可用性。群集管理器可以将任务分配给任何`ACTIVE`节点，因此到目前为止，所有节点都可用于接收任务。

有时，例如计划的维护时间，您需要将节点设置为`DRAIN`可用性。`DRAIN`可用性阻止节点从群集管理器接收新任务。它还意味着管理器停止在节点上运行的任务，并在具有`ACTIVE`可用性的节点上启动副本任务。

验证所有节点是否都可用。

```
[root@manager1 ~]# docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
164tibjpsoq80to1ktc4rp5ej     worker2             Ready               Active              
qfge07btc9daqarfrwm6q0hy7 *   manager1            Ready               Active              Leader
sr304jpfeprorr77olhqgqkkp     worker1             Ready               Active
```

如果还没有从`redis`运行该[滚动更新](https://docs.docker.com/engine/swarm/swarm-tutorial/rolling-update/)服务，请立即启动它：

```
docker service create --replicas 3 --name redis --update-delay 10s redis:3.0.6
```

运行`docker node update --availability drain <NODE-ID>`以排空已分配任务的节点：

检查节点以检查其可用性：

```
[root@manager1 ~]# docker node inspect --pretty worker1
ID:            sr304jpfeprorr77olhqgqkkp
Hostname:                  worker1
Joined at:                 2018-08-02 10:01:12.190726637 +0000 utc
Status:
 State:            Ready
 Availability:             Active
 Address:        192.168.237.129
Platform:
 Operating System:    linux
 Architecture:        x86_64
Resources:
 CPUs:            1
 Memory:        1.779GiB
Plugins:
 Network:        bridge, host, macvlan, null, overlay
 Volume:        local
Engine Version:        17.05.0-ce
```

Docker Engine群集模式可以轻松发布服务端口，使其可用于群组外的资源。所有节点都参与入口**路由网格**。路由网格允许群集中的每个节点接受已发布端口上的连接，以便在群集中运行的任何服务，即使节点上没有任何任务正在运行。路由网格将所有传入请求路由到可用节点上的已发布端口到活动容器。

要在群集中使用入口网络，您需要在启用群集模式之前在群集节点之间打开以下端口：

* 端口`7946`TCP / UDP用于容器网络发现。
* `4789`容器入口网络的端口UDP。

您还必须打开群集节点与需要访问端口的任何外部资源（如外部负载平衡器）之间的已发布端口。

您还可以[绕过](https://docs.docker.com/engine/swarm/ingress/#bypass-the-routing-mesh)给定服务[的路由网格](https://docs.docker.com/engine/swarm/ingress/#bypass-the-routing-mesh)。

**发布服务端口**

使用该`--publish`标志在创建服务时发布端口。`target`用于指定容器内的端口，`published`用于指定要在路由网格上绑定的端口。如果不离开`published`端口，则会为每个服务任务绑定一个随机的高编号端口。您需要检查任务以确定端口。

```
$ docker service create \
  --name <SERVICE-NAME> \
  --publish published=<PUBLISHED-PORT>,target=<CONTAINER-PORT> \
  <IMAGE>
```

**注意**：此语法的旧形式是冒号分隔的字符串，其中发布的端口是第一个，目标端口是第二个，例如`-p 8080:80`。新语法是首选，因为它更易于阅读并允许更大的灵活性。

这`<PUBLISHED-PORT>`是群集提供服务的端口。如果省略它，则绑定一个随机的高编号端口。它`<CONTAINER-PORT>`是容器侦听的端口。此参数是必需的。

例如，以下命令将nginx容器中的端口80发布到群集中任何节点的端口8080：

```
[root@manager1 ~]# docker service create \
>   --name my-web \
>   --publish published=8080,target=80 \
>   --replicas 2 \
>   nginx
ir1aln8w0387t5uq9408grc2r
Since --detach=false was not specified, tasks will be created in the background.
In a future release, --detach=false will become the default.
```

当您在任何节点上访问端口8080时，Docker会将您的请求路由到活动容器。在群集节点本身上，端口8080实际上可能不受约束，但路由网格知道如何路由流量并防止发生任何端口冲突。

路由网格在已发布的端口上侦听分配给该节点的任何IP地址。对于可外部路由的IP地址，该端口可从主机外部获得。对于所有其他IP地址，只能从主机内访问。

![](/files/-Lg5jP759yC9KaTjmXgg)

可以使用以下命令发布现有服务的端口：

```
$ docker service update \
  --publish-add published=<PUBLISHED-PORT>,target=<CONTAINER-PORT> \
  <SERVICE>
```

您可以使用`docker service inspect`查看服务的已发布端口。例如：

```
[root@manager1 ~]# docker service inspect --format="{{json .Endpoint.Spec.Ports}}" my-web
[{"Protocol":"tcp","TargetPort":80,"PublishedPort":8080,"PublishMode":"ingress"}]
```

输出显示`<CONTAINER-PORT>`（从容器标记为`TargetPort`）和`<PUBLISHED-PORT>`（标记`PublishedPort`），其中节点监听的服务请求。

仅为TCP或仅UDP发布端口

默认情况下，发布端口时，它是TCP端口。除了TCP端口之外，您还可以专门发布UDP端口。发布TCP和UDP端口时，如果省略协议说明符，则端口将作为TCP端口发布。如果使用较长的语法（建议用于Docker 1.13及更高版本），请将`protocol`密钥设置为`tcp`或`udp`。

仅限TCP

长**语法：**

```
$ docker service create --name dns-cache \
  --publish published=53,target=53 \
  dns-cache
```

短**语法：**

```
$ docker service create --name dns-cache \
  -p 53:53 \
  dns-cache
```

TCP和UDP

长**语法：**

```
$ docker service create --name dns-cache \
  --publish published=53,target=53 \
  --publish published=53,target=53,protocol=udp \
  dns-cache
```

短**语法：**

```
$ docker service create --name dns-cache \
  -p 53:53 \
  -p 53:53/udp \
  dns-cache
```

仅限UDP

长**语法：**

```
$ docker service create --name dns-cache \
  --publish published=53,target=53,protocol=udp \
  dns-cache
```

短**语法：**

```
$ docker service create --name dns-cache \
  -p 53:53/udp \
  dns-cache
```

绕过路由网格

您可以绕过路由网格，以便在访问给定节点上的绑定端口时，始终访问在该节点上运行的服务实例。这被称为`host`模式。有几点需要牢记。

* 如果访问未运行服务任务的节点，则该服务不会侦听该端口。没有任何东西可以监听，或者完全不同的应用程序正在收听。
* 如果您希望在每个节点上运行多个服务任务（例如，当您有5个节点但运行10个副本时），则无法指定静态目标端口。允许Docker分配一个随机的高编号端口（通过不离开`published`），或者确保只有一个服务实例在给定节点上运行，使用全局服务而不是复制服务，或者使用放置约束。

要绕过路由网格，必须使用长`--publish`服务并设置`mode`为`host`。如果省略该`mode`键或将其设置为`ingress`，则使用路由网格。以下命令使用`host`模式创建全局服务并绕过路由网格。

```
$ docker service create --name dns-cache \
  --publish published=53,target=53,protocol=udp,mode=host \
  --mode global \
  dns-cache
```

配置外部负载均衡器

您可以为群组服务配置外部负载平衡器，可以与路由网格结合使用，也可以根本不使用路由网格。

使用路由网格

您可以配置外部负载平衡器以将请求路由到群组服务。例如，您可以配置[HAProxy](http://www.haproxy.org/)以平衡对发布到端口8080的nginx服务的请求。

![](/files/-Lg5jP796Qgo4e8AoTOf)

在这种情况下，端口8080必须在负载平衡器和群中的节点之间打开。群集节点可以驻留在代理服务器可访问的专用网络上，但不能公开访问。

您可以配置负载平衡器以平衡群中每个节点之间的请求，即使节点上没有安排任务也是如此。例如，您可以在以下位置进行以下HAProxy配置`/etc/haproxy/haproxy.cfg`：

```
global
        log /dev/log    local0
        log /dev/log    local1 notice
...snip...

# Configure HAProxy to listen on port 80
frontend http_front
   bind *:80
   stats uri /haproxy?stats
   default_backend http_back

# Configure HAProxy to route requests to swarm nodes on port 8080
backend http_back
   balance roundrobin
   server node1 192.168.99.100:8080 check
   server node2 192.168.99.101:8080 check
   server node3 192.168.99.102:8080 check
```

当您在端口80上访问HAProxy负载平衡器时，它会将请求转发给群集中的节点。swarm路由网格将请求路由到活动任务。如果由于任何原因，swarm调度程序将任务分派给不同的节点，则无需重新配置负载均衡器。

您可以配置任何类型的负载均衡器以将请求路由到群集节点。要了解有关HAProxy的更多信息，请参阅[HAProxy文档](https://cbonte.github.io/haproxy-dconv/)。

没有路由网格

要使用不带路由网格的外部负载平衡器，请设置`--endpoint-mode`为`dnsrr`而不是默认值`vip`。在这种情况下，没有一个虚拟IP。相反，Docker为服务设置DNS条目，以便服务名称的DNS查询返回IP地址列表，客户端直接连接到其中一个。您有责任向负载均衡器提供IP地址和端口列表。请参阅[配置服务发现](https://docs.docker.com/engine/swarm/networking/#configure-service-discovery)。

#### 部署Stack

```
$ git clone https://github.com/openfaas/faas && \
  cd faas && \
  ./deploy_stack.sh
```

默认配置将为您创建用户名和密码组合：

```
Attempting to create credentials for gateway..
s7dt6cpbpcscldqxvtwovh0ds
h7p0duendgn6ua4ujrtz2gfjc
[Credentials]
username: admin
password: d9f13200be7af7f9fd2b8562e30e1ab9544cb952c5e72d9405910e1d6e714b6f
echo -n d9f13200be7af7f9fd2b8562e30e1ab9544cb952c5e72d9405910e1d6e714b6f | faas-cli login --username=admin --password-stdin

Enabling basic authentication for gateway..

Deploying OpenFaaS core services
unsupported Compose file version: 3.3
```

如您在控制台中看到的那样运行命令，不要复制/粘贴login命令。运行`faas-cli login`密码后，将存储为哈希值`~/.openfaas/config.yaml`。

#### 测试用户界面

在几秒钟内（如果在不良的WiFi连接上，则为几分钟），API网关和相关的OpenFaaS映像将被拉入您的本地Docker库，您将能够访问以下UI：

`http://127.0.0.1:8080`

#### 部署样本函数

前面`git clone`包括一组示例函数`stack.yml`，要部署它们，[请安装OpenFaaS CLI](https://docs.openfaas.com/cli/install/)并运行：

```
$ faas deploy -f \ 

  https://raw.githubusercontent.com/openfaas/faas/master/stack.yml
```

### 2.[基于Kubernetes部署](https://docs.openfaas.com/deployment/kubernetes/)

## 问题梳理

在（二）中操作后，我第一次未禁用防火墙时，会出现如下错误`unsupported Compose file version: 3.3`

```
[Credentials]\n username: admin \n password: c0f465cc473068c344cb0be6193c750f18da6d4d09679d53c05b47696c88ab7d\n echo -n c0f465cc473068c344cb0be6193c750f18da6d4d09679d53c05b47696c88ab7d | faas-cli login --username=admin --password-stdin

Enabling basic authentication for gateway..

Deploying OpenFaaS core services
unsupported Compose file version: 3.3
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://jahentao.gitbook.io/openfass/2openfassan-zhuang-bu-shu-he-shi-yong.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
