# k8s-addusers **Repository Path**: wanghuiic/k8s-addusers ## Basic Information - **Project Name**: k8s-addusers - **Description**: 在k8s deployment的容器里自动创建用户和组 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-11-09 - **Last Updated**: 2025-11-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: Kubernetes ## README # 为k8s deployment容器自动创建用户和组 目标:k8s容器启动之后,容器Linux操作系统已经创建了想要的用户。 例如,用户能够以自己的用户名,ssh登录容器。 这里的用户是指普通用户,要求uid>1000 && uid<60000。 ## k8s deployment如何配置 ### 1. 创建 configmap users-scripts.yaml,需要修改一行 ``` namespace: default ``` 修改为deployment的namespace。 然后创建 configmap, ``` kubectl apply -f users-scripts.yaml ``` users-scripts 包括 init.sh 和 post.sh 两个shell脚本。如下所示。 #### users-scripts.yaml ``` apiVersion: v1 kind: ConfigMap metadata: name: users-scripts namespace: default labels: app: users-scripts data: init.sh: | #!/bin/bash set -eu GROUP_IN=${GROUP_IN:-} USER_IN=${USER_IN:-} DEFAULT_PASS=${DEFAULT_PASS:-P@88w0rd} mkdir -p /inituser : > /inituser/group.txt : > /inituser/passwd.txt : > /inituser/shadow.txt # 收集“组→成员”映射 declare -A GROUP_MEMS # 内容将是 gid->"user1,user2" for u in $USER_IN; do [[ -z "$u" ]] && continue IFS=: read -r un _ uid gids _ _ <<<"$u" for g in ${gids//,/ }; do # 把用户加入该 gid 的成员列表 GROUP_MEMS[$g]="${GROUP_MEMS[$g]:-}${GROUP_MEMS[$g]:+,}${un}" done done # 记录用户声明的所有 gid(含主组+附加组) declare -A USER_GIDS # gid -> 1 for u in $USER_IN; do [[ -z "$u" ]] && continue IFS=: read -r un _ uid gids _ _ <<<"$u" for g in ${gids//,/ }; do USER_GIDS[$g]=1 done done declare -A PRINTED_GIDS # 写用户显式声明的组(GROUP_IN) for g in $GROUP_IN; do [[ -z "$g" ]] && continue IFS=: read -r gn gid <<<"$g" members=${GROUP_MEMS[$gid]:-} echo "${gn}:x:${gid}:${members}" >> /inituser/group.txt # 标记已输出 PRINTED_GIDS[$gid]=1 done # 补全缺失组(用户在 gids 里提到,但 GROUP_IN 没出现) for gid in "${!USER_GIDS[@]}"; do [[ ${PRINTED_GIDS[$gid]:-} ]] && continue # 已输出过,跳过 # 自动生成与用户同名、同 gid 的组 # 组名 = 第一个用到该 gid 的用户名(可自定义) for u in $USER_IN; do IFS=: read -r un _ uid gids _ _ <<<"$u" [[ " ${gids//,/ } " =~ " $gid " ]] || continue auto_gn=$un break done members=${GROUP_MEMS[$gid]:-} echo "${auto_gn}:x:${gid}:${members}" >> /inituser/group.txt done # 写出用户行(主组用第一个 gid) for u in $USER_IN; do [[ -z "$u" ]] && continue IFS=: read -r un upw uid gids home shell <<<"$u" [[ -z "$upw" ]] && upw="$DEFAULT_PASS" main_gid=${gids%%,*} # ---- 生成 SHA-512 密码哈希 ---- salt=$(tr -dc 'A-Za-z0-9' > /inituser/passwd.txt echo "${un}:${pwd_hash}:$(($(date +%s)/86400)):0:99999:7:::" >> /inituser/shadow.txt done echo -e "This directory is ephemeral and will be lost when the pod exits.\nDo NOT save any data or credentials here." > /inituser/_DO_NOT_WRITE_HERE.readme post.sh: | #!/bin/bash set -eu [[ -f /inituser/group.txt ]] && cat /inituser/group.txt >> /etc/group [[ -f /inituser/passwd.txt ]] && cat /inituser/passwd.txt >> /etc/passwd [[ -f /inituser/shadow.txt ]] && cat /inituser/shadow.txt >> /etc/shadow echo "users/groups merged into main container." rm -f /inituser/*.txt ``` ### 2. 配置deployment #### 2.1 定义volumes ```yaml volumes: - name: inituser emptyDir: sizeLimit: 1Mi - name: scripts configMap: name: users-scripts # 集群级 CM defaultMode: 0755 ``` #### 2.2 定义initContainer 需要的工作: 定义环境变量:GROUP_IN 和 USER_IN 可选的环境变量: DEFAULT_PASS ```yaml initContainers: - name: mk-users image: ubuntu:22.04 env: - name: GROUP_IN value: "devops:2001 data:2002" - name: USER_IN value: "alice:password:1001:1001,2002:/home/users/alice:/bin/bash bob::1002:2001,2002:::" - name: DEFAULT_PASS value: "P@88w0rd" command: ["/bin/bash","-c","/scripts/init.sh"] volumeMounts: - name: inituser mountPath: /inituser - name: scripts mountPath: /scripts readOnly: true securityContext: runAsUser: 0 ``` #### 2.3 主容器增加的配置 ```yaml lifecycle: postStart: exec: command: ["/bin/bash","-c","/inituser/scripts/post.sh"] volumeMounts: - name: inituser mountPath: /inituser - name: scripts mountPath: /inituser/scripts readOnly: true ``` ## 格式说明 ### 组信息 定义用户之前,先定义组。 GROUP_IN环境变量定义组信息。 一个组的信息包括 组名:组id。组之间用空格分开。例如, ``` devops:2001 project:2004 ``` 定义了devops和project两个组。 #### 用户登录组 在创建用户的时候,linux系统通常自动创建出跟用户同名同id的组,作为登录组,或称主组。 init.sh脚本会自动生成这个组。所以,不必在 GROUP_IN显式定义这类group。进一步参考后面的用户信息部分。 ### 用户信息 环境变量 USER_IN 给出用户信息。 #### 基本组成 一个用户的信息,由六项组成,用户信息字符串 ``` 用户名:初始密码:uid:gid_list:home:shell ``` 之间以冒号分隔。组id之间以逗号分隔。例如 ``` alice:password:1001:1001,2002:/home/alice:/bin/bash ``` #### 默认值 有的项可以省略, 必填三项:用户名,uid,gid列表。 密码默认值 P@88w0rd DEFAULT_PASS 环境变量可以覆盖上面的默认值。如果直接在用户信息字符串里给出了初始密码,将具有最高优先级。 用户home路径的默认值是 /home/<用户名> 用户shell的默认值是 /bin/bash #### 用户组列表 gid列表中第一个gid是用户的登录组,或称为主组。其他是附加组。 linux在创建用户的时候,通常会同时创建跟用户同名的组,并且gid也跟用户uid一致。在书写用户信息字符串的时候,这个组不能省略。例如, ``` alice::1001:1001,2002:: ``` gid=1001这个组可以不必在GROUP_IN中定义。init.sh会自动创建出来alice(1001)这个组。 注意不能写成 ``` alice::1001:2002:: ``` 此时,alice的主组是gid=2002的组,这个组必须在GROUP_IN中定义。 #### 多个用户 如果有多个用户,之间用空格分隔。例如 ``` alice:password:1001:1001,2002:/home/users/alice:/bin/bash bob::1002:2001,2002::" ```