8

当我尝试为EJBCA-ce创建 Azure 容器实例时,出现错误并且看不到任何日志。

我期望以下结果: 天蓝色门户容器实例事件成功

但我收到以下错误:

天蓝色门户容器实例事件失败

Failed to start container my-azure-container-resource-name, Error response: to create containerd task: failed to create container e9e48a_________ffba97: guest RPC failure: failed to find user by uid: 10001: expected exactly 1 user matched '0': unknown

一些上下文:

我在天蓝色云容器实例上运行容器

我试过了

  • 来自 ARM 模板
  • 来自 Azure 门户。
  • 已安装文件共享
  • 使用数据库环境变量
  • 没有任何环境变量

它使用相同的环境变量(数据库配置)在本地运行良好。几周前它曾经使用相同的配置运行。

以下是我从 az cli 附加容器组时获得的一些日志。

(count: 1) (last timestamp: 2020-11-03 16:04:32+00:00) pulling image "primekey/ejbca-ce:6.15.2.3"
(count: 1) (last timestamp: 2020-11-03 16:04:37+00:00) Successfully pulled image "primekey/ejbca-ce:6.15.2.3"
(count: 28) (last timestamp: 2020-11-03 16:27:52+00:00) Error: Failed to start container aci-pulsy-ccm-ejbca-snd, Error response: to create containerd task: failed to create container e9e48a06807fba124dc29633dab10f6229fdc5583a95eb2b79467fe7cdffba97: guest RPC failure: failed to find user by uid: 10001: expected exactly 1 user matched '0': unknown

从 dockerhub提取的dockerfile

我怀疑这个问题可能与命令有关USER 0USER 10001我们在 dockerfile 中发现了好几次。

COPY dir:89ead00b20d79e0110fefa4ac30a827722309baa7d7d74bf99910b35c665d200 in /
/bin/sh -c rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
CMD ["/bin/bash"]
USER 0
COPY dir:893e424bc63d1872ee580dfed4125a0bef1fa452b8ae89aa267d83063ce36025 in /opt/primekey
COPY dir:756f0fe274b13cf418a2e3222e3f6c2e676b174f747ac059a95711db0097f283 in /licenses
USER 10001
CMD ["/opt/primekey/wildfly-14.0.1.Final/bin/standalone.sh" "-b" "0.0.0.0"
MAINTAINER PrimeKey Solutions AB
ARG releaseTag
ARG releaseEdition

ARM 模板

{
      "type": "Microsoft.ContainerInstance/containerGroups",
      "apiVersion": "2019-12-01",
      "name": "[variables('ejbcaContainerGroupName')]",
      "location": "[parameters('location')]",
      "tags": "[variables('tags')]",
      "dependsOn": [
        "[resourceId('Microsoft.DBforMariaDB/servers', variables('ejbcaMariadbServerName'))]",
        "[resourceId('Microsoft.DBforMariaDB/servers/databases', variables('ejbcaMariadbServerName'), variables('ejbcaMariadbDatabaseName'))]"
      ],
      "properties": {
        "sku": "Standard",
        "containers": [
          {
            "name": "[variables('ejbcaContainerName')]",
            "properties": {
              "image": "primekey/ejbca-ce:6.15.2.3",
              "ports": [
                {
                  "protocol": "TCP",
                  "port": 443
                },
                {
                  "protocol": "TCP",
                  "port": 8443
                }
              ],
              "environmentVariables": [

                {
                  "name": "DATABASE_USER",
                  "value": "[concat(parameters('mariadbUser'),'@', variables('ejbcaMariadbServerName'))]"
                },
                {
                  "name": "DATABASE_JDBC_URL",
                  "value": "[variables('ejbcaEnvVariableJdbcUrl')]"
                },
                {
                  "name": "DATABASE_PASSWORD",
                  "secureValue": "[parameters('mariadbAdminPassword')]"
                }
              ],
              "resources": {
                "requests": {
                  "memoryInGB": 1.5,
                  "cpu": 2
                }
              }
              ,
               "volumeMounts": [
                 {
                   "name": "certificates",
                   "mountPath": "/mnt/external/secrets"
                 }
               ]
            }
          }
        ],
        "initContainers": [],
        "restartPolicy": "OnFailure",
        "ipAddress": {
          "ports": [
                {
                  "protocol": "TCP",
                  "port": 443
                },
                {
                  "protocol": "TCP",
                  "port": 8443
                }
          ],
          "type": "Public",
          "dnsNameLabel": "[parameters('ejbcaContainerGroupDNSLabel')]"
        },
        "osType": "Linux",
         "volumes": [
           {
             "name": "certificates",
             "azureFile": {
               "shareName": "[parameters('ejbcaCertsFileShareName')]",
               "storageAccountName": "[parameters('ejbcaStorageAccountName')]",
               "storageAccountKey": "[parameters('ejbcaStorageAccountKey')]"
             }
           }
         ]
      }
    }

它在我的本地机器上运行良好(ubuntu 20.04)

docker run -it --rm -p 8080:8080 -p 8443:8443 -h localhost -e DATABASE_USER="mymaridbuser@my-db" -e DATABASE_JDBC_URL="jdbc:mariadb://my-azure-domain.mariadb.database.azure.com:3306/ejbca?useSSL=true" -e DATABASE_PASSWORD="my-pwd" primekey/ejbca-ce:6.15.2.3
4

2 回答 2

6

在 EJBCA-ce 容器映像中,我认为他们试图提供不同于root运行 EJBCA 服务器的用户。根据Docker 文档

USER 指令设置用户名(或 UID)和可选的用户组(或 GID),以在运行映像时以及 Dockerfile 中跟随它的任何 RUN、CMD 和 ENTRYPOINT 指令使用

Dockerfile他们引用了两个用户,root对应于 UID0和另一个用户,对应于 UID 10001

通常,在 Linux 和 UNIX 系统中,UID 可以组织在不同的范围内:它在很大程度上取决于具体的操作系统和用户管理实践,但很可能在 linux 系统中创建的第一个用户帐户将分配给 UID1001或者10001,就像在这种情况下。请参阅维基百科或本文中的 UID 条目

AFAIK,USER指示不需要存在于您的容器中才能正确运行它:事实上,如果您在本地运行它,它将启动而没有进一步的问题。

具有 UID 的用户实际上将通过在 , 中定义10001的脚本运行在您的容器中,由以下代码片段设置:CMDDockerfile/opt/primekey/bin/start.sh

if ! whoami &> /dev/null; then
  if [ -w /etc/passwd ]; then
    echo "${APPLICATION_NAME}:x:$(id -u):0:${APPLICATION_NAME} user:/opt:/sbin/nologin" >> /etc/passwd
  fi
fi

请注意,APPLICATION_NAME在此上下文中采用该值 ejbca,并且运行此脚本的用户(如 中所示Dockerfile)是10001. 这将是id -u此代码中的命令提供的值。

如果您在本地运行容器,则可以验证它:

docker run -it -p 8080:8080 -p 8443:8443 -h localhost primekey/ejbca-ce:6.15.2.3

并开始bash

 docker exec -it container_name /bin/bash

如果你跑whoami,它会告诉你ejbca

如果你运行id它会给你以下输出:

uid=10001(ejbca) gid=0(root) groups=0(root)

您也可以验证用户是否存在/etc/passwd

bash-4.2$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
ejbca:x:10001:0:ejbca user:/opt:/sbin/nologin

Pierre 没有得到这个输出的原因是因为他运行的容器覆盖了提供CMD的,因此没有执行start.sh负责创建用户的脚本,如上所述。

出于任何原因,这是我的知识使我失败的地方,当 Azure 尝试运行您的容器时,它失败了,因为在 中USER 10001标识的Dockerfile不存在。

我认为这可能与使用 ofcontainerd而不是docker.

Azure 报告的错误似乎与 Microsoft 项目opengcs 有关

他们说这个项目:

Open Guest Compute Service 是一个 Linux 开源项目,旨在进一步开发 Windows 上 Linux Hyper-V 容器 (LCOW) 的生产质量实现。它旨在在自定义 Linux 操作系统中运行,以支持 Linux 容器有效负载。

和:

LCOW v2 作为 LCOW v1 的替代品的重点是通过 containerd/containerd 及其 Runtime V2 接口的协调和工作。要查看我们的容器主机端 shim,请查看此处 Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1。

您在控制台中看到的错误是由您可以在他们的代码库中找到的文件引发spec.go,当他们试图建立代表应该运行容器进程的用户时:

func setUserID(spec *oci.Spec, uid int) error {
    u, err := getUser(spec, func(u user.User) bool {
        return u.Uid == uid
    })
    if err != nil {
        return errors.Wrapf(err, "failed to find user by uid: %d", uid)
    }
    spec.Process.User.UID, spec.Process.User.GID = uint32(u.Uid), uint32(u.Gid)
    return nil
}

此代码由其他代码片段执行 - 您可以在此处查看完整的功能代码

parts := strings.Split(userstr, ":")
switch len(parts) {
case 1:
    v, err := strconv.Atoi(parts[0])
    if err != nil {
        // evaluate username to uid/gid
        return setUsername(spec, userstr)
    }
    return setUserID(spec, int(v))

getUser功能:

func getUser(spec *oci.Spec, filter func(user.User) bool) (user.User, error) {
    users, err := user.ParsePasswdFileFilter(filepath.Join(spec.Root.Path, "/etc/passwd"), filter)
    if err != nil {
        return user.User{}, err
    }
    if len(users) != 1 {
        return user.User{}, errors.Errorf("expected exactly 1 user matched '%d'", len(users))
    }
    return users[0], nil
}

如您所见,这些正是 Azure 向您报告的错误。

总而言之,我认为他们提供了一个符合OCI 图像格式规范的 Windows LCOW 解决方案,适用于运行带有containerd.

正如您所指出的,如果它在几周前使用相同的配置运行,我最好的客人可能是,他们将您的容器从纯 Linuxcontainerd运行时实现切换到基于 Windows 和上述软件的容器,这就是为什么你的容器现在失败了。

一种可能的解决方法可能是根据 PrimeKey 提供的官方创建自定义图像并创建 user 10001,正如 Pierre 指出的那样。

要完成此任务,首先,创建一个新的自定义Dockerfile. 您可以尝试,例如:

FROM primekey/ejbca-ce:6.15.2.3

USER 0

RUN echo "ejbca:x:10001:0:ejbca user:/opt:/sbin/nologin" >> /etc/passwd

USER 10001

请注意,您可能需要从官方 EJBCA 映像中定义一些环境变量。

有了这个Dockerfile,您可以docker使用适当的docker-compose.yaml文件构建图像或 docker compose,例如:

version: "3"

services:
  ejbca:
    image: <your repository>/ejbca
    build: .
    ports:
      - "8080:8080"
      - "8443:8443"

请根据您认为合适的方式对其进行自定义。

通过此设置,新容器仍将在本地环境中以与原始容器相同的方式正常运行:我希望在 Azure 中也是如此。

于 2020-11-19T09:37:23.207 回答
2

10001您的图像中不存在具有 UID 的用户。这不会阻止USERDockerfile 中的命令正常工作或图像本身无效,但它似乎会导致 Azure 容器出现问题。

我找不到文档或任何关于为什么它在 Azure 上不起作用的参考资料(如果是这样,将更新),但在图像中添加用户应该可以解决问题。尝试在 Dockerfile 中添加类似这样的内容来创建具有 UID 的用户10001(这必须以 root 身份完成,即使用 user 0):

useradd -u 10001 myuser

10001不存在查看用户的附加说明:

# When running container, not recognized by system
$ docker run docker.io/primekey/ejbca-ce:6.15.2.3 whoami
whoami: cannot find name for user ID 10001

# Not present in /etc/passwd
$ docker run docker.io/primekey/ejbca-ce:6.15.2.3 cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
于 2020-11-17T09:06:55.253 回答