当 ssh 命令为 运行 时,Gitlab CI 作业挂起

Gitlab CI job hangs when ssh command is run

作业运行是通过 SSH(打开 ssh)在其他服务器上的脚本。脚本执行成功,因此连接成功。 问题是它永远不会断开连接。永久保持 运行ning 状态,最后超时终止(如果之前没有手动停止)。

失败的命令是:

- ssh -o StrictHostKeyChecking=no root@server -p 22 '/home/script.sh'

我可以在服务器上看到脚本 运行 是如何正确的。 ssh 连接似乎永远不会关闭。 在该命令之后,作业不会执行任何其他操作,并且会无限加载。

When the script is executed from the server itself it also works correctly.


我已经尝试过的东西

我试过以不同的方式添加 exit 命令

- ssh -o StrictHostKeyChecking=no root@server -p 22 '/home/script.sh && exit'

- ssh -o StrictHostKeyChecking=no root@server -p 22 '/home/script.sh && exit 0'

- ssh -o StrictHostKeyChecking=no root@server -p 22 '/home/script.sh ; exit'

- ssh -o StrictHostKeyChecking=no root@server -p 22 '/home/script.sh ; exit 0'

我也试过在

之后加一行
- ssh -o StrictHostKeyChecking=no root@server -p 22 '/home/script.sh'
- exit

我也试过添加后台运行命令&

- ssh -o StrictHostKeyChecking=no root@server -p 22 '/home/script.sh &'
- exit

- ssh -o StrictHostKeyChecking=no root@server -p 22 '/home/script.sh &'

- ssh -o StrictHostKeyChecking=no root@server -p 22 '/home/script.sh & ; exit'

- ssh -o StrictHostKeyChecking=no root@server -p 22 '/home/script.sh & ; exit 0'

我也试过杀掉 ssh 进程

# add this line after the problematic (in its diferent ways) 
 - eval $(ssh-agent -k)

完整脚本gitlab-ci.yml:

# This file is a template, and might need editing before it works on your project.
# Build JAVA applications using Apache Maven (http://maven.apache.org)
# For docker image tags see https://hub.docker.com/_/maven/

# This template uses jdk8 for verifying and deploying images
image: maven:3.6.0-jdk-8

stages:
  - build
  - deploy
  - notify
  
build:
  stage: build
  only:
    - dev
  script: "mvn clean install -Dactive.profile=dev -DskipTests -B"
  artifacts:
    paths:
      - target/*.jar
      - notifydeploy.sh
      - $DEV_SSH

deploy:
  stage: deploy
  only:
    - dev
  before_script:
    - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
    # Run ssh-agent (inside the build environment)
    - eval $(ssh-agent -s)
    # Add the SSH key stored in SSH_PRIVATE_KEY variable to the agent store
    - ssh-add <(echo "$DEV_SSH")
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
  script:
    - scp -P 22 ./target/*.jar root@server:/home
    - ssh -o StrictHostKeyChecking=no root@server -p 22 '/home/script.sh'
    - eval $(ssh-agent -k)

notify_fail:
  stage: notify
  allow_failure: true
  only:
    - dev
  when: on_failure
  script:
    - echo "FAIL"
    
notify_success:
  stage: notify
  allow_failure: true
  only:
    - Deploy_to_dev03
  script:
    - chmod +x ./notifydeploy.sh
    - ./notifydeploy.sh

While the gitlab process is waiting for the command that hangs it, if the same script is executed from the server, the job is unlocked and ends correctly...

当使用 ps aux | grep script.sh 在服务器上查找进程时,当作业执行时它会显示,但随后它会消失,因此它不会挂在服务器上。

有什么解决办法吗?我想不出还能尝试什么..

script.sh 就像:

#!/bin/bash

status_code=$(curl --write-out %{http_code} --silent --output /dev/null http://server/url/)
status_code_n=$(curl --write-out %{http_code} --silent --output /dev/null http://localhost:8761)
#Si no es igual a 404 es que esta funcionando
if [[ "$status_code" == 200  &&  "$status_code_n" == 200 ]] ; then  
    echo "Estatus c $status_code"  
    echo "Estatus n $status_code_n"
    pkill -f jar-process
    sleep 1 
    /usr/bin/java -jar -Dspring.profiles.active=dev /home/jar-process*.jar &
    sleep 1
    status_code_t=$(curl --write-out %{http_code} --silent --output /dev/null http://localhost:8090/api/)
    if [[ "$status_code_t" == 401 ]] ; then  
        echo "Estatus $status_code_t (401 is OK)"
        echo "La API se ha desplegado correctamente"
        exit 0
    else
        echo "Estatus $status_code_t"
        echo "Se ha producido algun error al desplegar"
        exit 1
    fi
else
    echo "Estatus c $status_code"
    echo "Estatus n $status_code_n"
    exit 1
fi

简短的回答是为脚本的 java 命令重定向标准文件描述符(标准输入、输出和错误),如下所示:

/usr/bin/java ... /home/jar-process*.jar > /dev/null 2>&1 < /dev/null &

这会阻止 java 进程继承脚本的标准输出等。这就是阻止 ssh 关闭连接的原因。

更长的答案:当您 运行 一个 ssh 命令,例如:

ssh user@remote '/home/script.sh'

远程ssh服务器会创建一组管道作为远程命令的标准输入、输出和错误。启动命令后,ssh 服务器将保持通道打开,直到它在与远程命令的标准输出关联的管道上看到文件结束条件。

您的脚本正在启动一个进程,该进程应该在脚本退出后保持 运行ning。该进程继承了 ssh 创建的管道作为其标准描述符。该进程理论上可以写入其标准输出,因此在进程退出或关闭其标准输出之前,ssh 服务器不会在标准输出管道上看到文件结束条件。

您可以像这样重定向整个脚本的输出:

ssh user@remote '/home/script.sh >/dev/null 2>&1 < /dev/null'

但是,在您的情况下,脚本在失败时似乎会生成一条错误消息。重定向整个脚本的输出将阻止您看到错误消息。