From a4ac6b72fc4cd5e46667f73f0c816979ad2d92b6 Mon Sep 17 00:00:00 2001 From: wangruidong <940853815@qq.com> Date: Thu, 4 Jun 2026 14:53:51 +0800 Subject: [PATCH] perf: add jms_ansible_ee CI workflow and refine EE build --- .github/workflows/build-jms-ansible-ee.yml | 95 +++++++++++++++++++ apps/ops/ansible/runner.py | 87 +++++++++++------ utils/ansible_executor/bindep.txt | 29 +++--- utils/ansible_executor/build.sh | 2 +- .../execution-environment.yml | 22 +---- .../ansible_executor/requirements-python.txt | 2 +- 6 files changed, 173 insertions(+), 64 deletions(-) create mode 100644 .github/workflows/build-jms-ansible-ee.yml diff --git a/.github/workflows/build-jms-ansible-ee.yml b/.github/workflows/build-jms-ansible-ee.yml new file mode 100644 index 000000000..108e157f9 --- /dev/null +++ b/.github/workflows/build-jms-ansible-ee.yml @@ -0,0 +1,95 @@ +name: Build and Push Ansible EE Image + +on: + pull_request: + branches: + - 'dev' + - 'v*' + paths: + - utils/ansible_executor/** + - apps/libs/ansible/** + types: + - opened + - synchronize + - reopened + workflow_dispatch: + inputs: + branch: + description: '构建 Ansible EE 镜像所用的分支' + required: true + type: string + default: 'main' + +jobs: + build-and-push: + runs-on: ubuntu-latest + + steps: + - name: Lock Pull Request + if: github.event_name == 'push' + run: | + curl -X POST -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + -d '{"state":"pending", "description":"Action running, merge disabled", "context":"Lock PR"}' \ + "https://api.github.com/repos/${{ github.repository }}/statuses/${{ github.sha }}" + + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: ${{ github.event_name == 'workflow_dispatch' && inputs.branch || github.ref }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to DockerHub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Extract date + id: vars + run: echo "IMAGE_TAG=$(date +'%Y%m%d_%H%M%S')" >> $GITHUB_ENV + + - name: Install ansible-builder + run: pip install 'ansible-builder>=3.1.1' + + - name: Create EE build context + working-directory: utils/ansible_executor + run: | + ansible-builder create \ + -f execution-environment.yml \ + -c context \ + --container-runtime docker + + - name: Build and push multi-arch image + uses: docker/build-push-action@v6 + with: + platforms: linux/amd64,linux/arm64 + push: true + context: utils/ansible_executor/context + file: utils/ansible_executor/context/Dockerfile + tags: jumpserver/jms_ansible_ee:${{ env.IMAGE_TAG }} + + - name: Update runner.py + run: | + sed -i "s|ANSIBLE_EE_IMAGE = .*|ANSIBLE_EE_IMAGE = 'jumpserver/jms_ansible_ee:${{ env.IMAGE_TAG }}'|" apps/ops/ansible/runner.py + + - name: Commit changes + run: | + git config --global user.name 'github-actions[bot]' + git config --global user.email 'github-actions[bot]@users.noreply.github.com' + git add apps/ops/ansible/runner.py + git commit -m "perf: Update Ansible EE image tag in runner.py" + git push + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Unlock Pull Request + if: github.event_name == 'push' + run: | + curl -X POST -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + -d '{"state":"success", "description":"Action running, merge disabled", "context":"Lock PR"}' \ + "https://api.github.com/repos/${{ github.repository }}/statuses/${{ github.sha }}" diff --git a/apps/ops/ansible/runner.py b/apps/ops/ansible/runner.py index 59a801560..e0e1e7a9e 100644 --- a/apps/ops/ansible/runner.py +++ b/apps/ops/ansible/runner.py @@ -13,9 +13,26 @@ from ..utils import get_ansible_log_verbosity __all__ = ['AdHocRunner', 'PlaybookRunner', 'SuperPlaybookRunner', 'UploadFileRunner'] +ANSIBLE_EE_IMAGE = 'jms_ansible_ee:latest' + + +def use_ansible_docker_isolation(): + """Production runs ansible in EE container; dev runs in celery worker.""" + return not settings.DEBUG_DEV + + +def docker_isolation_kwargs(): + return { + 'process_isolation': True, + 'process_isolation_executable': 'docker', + 'container_image': ANSIBLE_EE_IMAGE, + } + def prepare_isolated_ansible_cfg(project_dir): """Copy ansible.cfg into job dir so the EE container picks up SSH settings.""" + if not use_ansible_docker_isolation(): + return src = os.path.join(settings.APPS_DIR, 'libs', 'ansible', 'ansible.cfg') dst = os.path.join(project_dir, 'ansible.cfg') shutil.copyfile(src, dst) @@ -69,23 +86,24 @@ class AdHocRunner: prepare_isolated_ansible_cfg(self.project_dir) - interface.run( - process_isolation=True, - process_isolation_executable='docker', - container_image='company-ee:1.0', - timeout=self.timeout if self.timeout > 0 else None, - extravars=self.extra_vars, - envvars=self.envs, - host_pattern=self.pattern, - private_data_dir=self.project_dir, - inventory=self.inventory, - module=self.module, - module_args=self.module_args, - verbosity=verbosity, - event_handler=self.cb.event_handler, - status_handler=self.cb.status_handler, - **kwargs - ) + run_kwargs = { + 'timeout': self.timeout if self.timeout > 0 else None, + 'extravars': self.extra_vars, + 'envvars': self.envs, + 'host_pattern': self.pattern, + 'private_data_dir': self.project_dir, + 'inventory': self.inventory, + 'module': self.module, + 'module_args': self.module_args, + 'verbosity': verbosity, + 'event_handler': self.cb.event_handler, + 'status_handler': self.cb.status_handler, + **kwargs, + } + if use_ansible_docker_isolation(): + run_kwargs.update(docker_isolation_kwargs()) + + interface.run(**run_kwargs) return self.cb @@ -123,10 +141,13 @@ class PlaybookRunner: prepare_isolated_ansible_cfg(self.project_dir) kwargs = dict(kwargs) + if use_ansible_docker_isolation(): + kwargs.update(docker_isolation_kwargs()) + elif self.isolate and not is_macos(): + kwargs['process_isolation'] = True + kwargs['process_isolation_executable'] = 'bwrap' + interface.run( - process_isolation=True, - process_isolation_executable='docker', - container_image='company-ee:1.0', private_data_dir=self.project_dir, inventory=self.inventory, playbook=self.playbook, @@ -160,17 +181,21 @@ class UploadFileRunner: def run(self, verbosity=0, **kwargs): verbosity = get_ansible_log_verbosity(verbosity) - interface.run( - private_data_dir=self.project_dir, - host_pattern="*", - inventory=self.inventory, - module='copy', - module_args=f"src={self.src_paths}/ dest={self.dest_path}/", - verbosity=verbosity, - event_handler=self.cb.event_handler, - status_handler=self.cb.status_handler, - **kwargs - ) + run_kwargs = { + 'private_data_dir': self.project_dir, + 'host_pattern': "*", + 'inventory': self.inventory, + 'module': 'copy', + 'module_args': f"src={self.src_paths}/ dest={self.dest_path}/", + 'verbosity': verbosity, + 'event_handler': self.cb.event_handler, + 'status_handler': self.cb.status_handler, + **kwargs, + } + if use_ansible_docker_isolation(): + run_kwargs.update(docker_isolation_kwargs()) + + interface.run(**run_kwargs) try: shutil.rmtree(self.src_paths) except OSError as e: diff --git a/utils/ansible_executor/bindep.txt b/utils/ansible_executor/bindep.txt index e133c68da..68797e3f0 100644 --- a/utils/ansible_executor/bindep.txt +++ b/utils/ansible_executor/bindep.txt @@ -1,20 +1,25 @@ # RPM packages for JumpServer ansible playbooks and custom modules. # ansible-builder 只支持 dnf/microdnf,不支持 Debian apt。 +# [compile] 仅在 builder 阶段安装,不进入最终镜像(见 ansible-builder bindep 文档)。 # freetds-devel / sshpass 需配合 execution-environment.yml 中 EPEL 启用步骤。 -gcc [platform:rpm] -pkgconf-pkg-config [platform:rpm] -python3.11-devel [platform:rpm] + +gcc [compile platform:rpm] +pkgconf-pkg-config [compile platform:rpm] +python3.11-devel [compile platform:rpm] +mariadb-connector-c-devel [compile platform:rpm] +postgresql-devel [compile platform:rpm] +freetds-devel [compile platform:rpm] +krb5-devel [compile platform:rpm] +openldap-devel [compile platform:rpm] +cyrus-sasl-devel [compile platform:rpm] +libX11-devel [compile platform:rpm] + openssh-clients [platform:rpm] sshpass [platform:rpm] iputils [platform:rpm] -nmap [platform:rpm] -telnet [platform:rpm] -mariadb-connector-c-devel [platform:rpm] -postgresql-devel [platform:rpm] -freetds-devel [platform:rpm] -krb5-devel [platform:rpm] -openldap-devel [platform:rpm] -cyrus-sasl-devel [platform:rpm] -libX11-devel [platform:rpm] +mariadb-connector-c [platform:rpm] +libpq [platform:rpm] +freetds [platform:rpm] +libX11 [platform:rpm] ca-certificates [platform:rpm] glibc-langpack-en [platform:rpm] diff --git a/utils/ansible_executor/build.sh b/utils/ansible_executor/build.sh index 51e04dc12..3a4014ea1 100755 --- a/utils/ansible_executor/build.sh +++ b/utils/ansible_executor/build.sh @@ -5,7 +5,7 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" cd "$SCRIPT_DIR" -IMAGE_TAG="${IMAGE_TAG:-company-ee:1.0}" +IMAGE_TAG="${IMAGE_TAG:-jms_ansible_ee:latest}" EE_FILE="${EE_FILE:-execution-environment.yml}" GITHUB_MIRROR="${GITHUB_MIRROR:-https://ghfast.top/}" USE_CHINA_MIRROR="${USE_CHINA_MIRROR:-1}" diff --git a/utils/ansible_executor/execution-environment.yml b/utils/ansible_executor/execution-environment.yml index ea2863bbe..37c48ed2f 100644 --- a/utils/ansible_executor/execution-environment.yml +++ b/utils/ansible_executor/execution-environment.yml @@ -1,26 +1,7 @@ --- -# JumpServer Ansible Execution Environment -# -# 国内加速构建(推荐): -# cd utils/ansible_executor -# chmod +x build.sh -# ./build.sh -# -# 手动构建: -# ansible-builder build -f execution-environment.yml -t company-ee:1.0 --container-runtime docker -# -# 加速要点: -# 1. pip: 清华源 (files/pip.conf) -# 2. dnf/epel: 阿里云 (files/use-china-mirrors.sh) -# 3. GitHub zip: build.sh 默认走 ghfast.top 镜像 -# 4. 重复构建: PKGMGR_PRESERVE_CACHE=always 保留 dnf 缓存 -# 5. Docker Desktop -> Settings -> Docker Engine 配置 registry-mirrors version: 3 -build_arg_defaults: - # 重复 build 时保留 dnf 缓存,显著加快二次构建 - PKGMGR_PRESERVE_CACHE: always images: # ansible-builder 仅支持 RPM 系镜像 (dnf),不能用 python:3.11-slim 等 Debian 镜像 @@ -79,3 +60,6 @@ additional_build_steps: - ENV ANSIBLE_FORCE_COLOR=True - ENV LC_ALL=C.UTF-8 - ENV LANG=C.UTF-8 + # bindep [compile] 已避免工具链进入最终层;此处仅清理 PKGMGR_PRESERVE_CACHE 写入的 dnf 缓存 + - RUN $PKGMGR clean all && rm -rf /var/cache/dnf /var/cache/yum /root/.cache + - RUN pip cache purge diff --git a/utils/ansible_executor/requirements-python.txt b/utils/ansible_executor/requirements-python.txt index 3f3af4f9d..05978f43a 100644 --- a/utils/ansible_executor/requirements-python.txt +++ b/utils/ansible_executor/requirements-python.txt @@ -2,7 +2,7 @@ paramiko==3.2.0 sshtunnel==0.4.0 pywinrm==0.4.3 -python-nmap==0.7.1 +telnetlib3==4.0.2 mysqlclient==2.2.4 pymssql==2.3.4 pymongo==4.6.3