在Azure上创建ejbca docker容器时出现容器错误“无法通过uid查找用户”

问题描述

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

我希望得到以下结果:

azure portal container instance events success

但是出现以下错误

azure portal container instance events failure

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

某些上下文:

我在Azure云容器实例上运行容器

我尝试过

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

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

当我从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

the dockerfile from dockerhub

的摘录

我怀疑问题可能与我们在dockerfile中多次发现的命令USER 0USER 10001有关。

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": 8443
                }
          ],"type": "Public","dnsNameLabel": "[parameters('ejbcaContainerGroupDNSLabel')]"
        },"osType": "Linux","volumes": [
           {
             "name": "certificates","azureFile": {
               "shareName": "[parameters('ejbcaCertsFileShareName')]","storageAccountName": "[parameters('ejbcaStorageAccountName')]","storageAccountKey": "[parameters('ejbcaStorageAccountKey')]"
             }
           }
         ]
      }
    }

它在linux(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

解决方法

在EJBCA-ce容器映像中,我认为他们正在尝试提供与root不同的用户来运行EJBCA服务器。根据{{​​3}}:

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

Dockerfile中,他们引用了两个用户root(对应于UID 0)和另一个用户(其UID为10001)。

通常,在Linux和UNIX系统中,UID可以组织在不同的范围内:它很大程度上取决于具体的操作系统和用户管理实践,但是很有可能在Linux系统中创建的第一个用户帐户是分配给UID 100110001,例如在这种情况下。请查看例如Docker documentationUID entry in wikipedia

AFAIK,指示的USER不需要存在于容器中即可正确运行:实际上,如果在本地运行,它将启动而不会出现更多问题。

实际上,将通过此代码在10001CMD中定义的Dockerfile中运行的脚本中,将UID为/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没有存在。

我认为这可能与使用containerd而不是docker有关。

Azure报告的错误似乎与Microsoft项目this article有关。

他们对这个项目说:

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

并且:

将LCOW v2替换为LCOW v1的重点是通过容器/容器及其运行时V2接口的协调和工作。要查看我们的容器式主机端填充程序,请在此处查看Microsoft / hcsshim / cmd / containerd-shim-runhcs-v1。

在控制台中看到的错误是opengcsspec.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))

此代码由另一个代码片段执行-您可以看到raised

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
}

还有full function code here函数:

containerd

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

作为总结,我认为他们正在提供Windows LCOW解决方案,该解决方案符合getUser,适用于使用containerd运行容器。

正如您所指出的,如果它在几周前曾经以相同的配置运行,我最好的客人是,也许他们将您的容器从纯Linux 10001运行时实现转换为一个基于Windows和上述软件的容器,这就是为什么容器现在出现故障的原因。

一种可行的解决方法是根据PrimeKey提供的官方文件创建自定义图像,并创建用户Dockerfile,正如Pierre所指出的那样。

要完成此任务,首先,创建一个新的自定义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 。您可以尝试,例如:

Dockerfile

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

使用此docker,您可以使用docker-compose.yaml来构建映像,或者使用适当的version: "3" services: ejbca: image: <your repository>/ejbca build: . ports: - "8080:8080" - "8443:8443" 文件来构建docker,例如:

{{1}}

请根据需要对其进行自定义。

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

,

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

我找不到文档或任何有关为什么它在Azure上不起作用的参考(如果可以,将进行更新),但是在图像中添加用户应该可以解决该问题。尝试在Dockerfile中添加类似的内容以创建具有UID 10001的用户(必须以root用户身份完成,即使用用户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