AEM provides runmode agnostic way of deploying packages unless you have different deployments going to those instances.
In most of the general use-cases the deployment package is same for author and publish and so is the deployment path, all that changes is the host. We build a separate pom project for deployment purposes, which can directly push any kind of package to any node specified as CI Job param. In our case we used it only for deploying a complete application package.
POM looks something like this -
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>cms-parent</artifactId>
<groupId>com.myproject.cms</groupId>
<version>1.0.2</version>
</parent>
<artifactId>cms-deploy</artifactId>
<groupId>com.myproject.cms.deploy</groupId>
<packaging>pom</packaging>
<version>1.0.0</version>
<name>
AEM :: Deploy
</name>
<properties>
<app.cms.myproject.complete.version>1.0.0-SNAPSHOT</app.cms.myproject.complete.version>
</properties>
<build>
<plugins>
<!-- additionally deploy three further content-packages which are not part of the complete-package -->
<plugin>
<groupId>com.day.jcr.vault</groupId>
<artifactId>content-package-maven-plugin</artifactId>
<executions>
<execution>
<!-- override the default execution defined in the cq-parent by binding it to some invalid phase -->
<id>default-package</id>
<goals>
<goal>package</goal>
</goals>
<phase>foobar</phase>
</execution>
<execution>
<!-- override the default execution for install-package, which is called whenever you call deploy -->
<id>install-package</id>
<goals>
<goal>install</goal>
</goals>
<phase>foobar</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>install-myproject-complete</id>
<build>
<plugins>
<plugin>
<artifactId>content-package-maven-plugin</artifactId>
<groupId>com.day.jcr.vault</groupId>
<executions>
<!-- deploy the scripts and classes (part of the release) -->
<execution>
<id>install-myproject-complete</id>
<goals>
<goal>install</goal>
</goals>
<configuration>
<artifactId>myproject-complete</artifactId>
<groupId>com.myproject.cms.msites</groupId>
<version>${app.cms.myproject.complete.version}</version>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
The you could create a maven project in CI (i am referring to Jenkins as CI, you could adapt to your server) and set it up as a parameterized build that accepts host
and deployment version

Next would be to configure the Source Code Management to point to above pom project in your SCM and configure maven build step -

In goals and options specify -
For Author deployment -
-U clean install -Pinstall-myproject-complete -Dcrx.host=${host}-author.mysite.com -Dcrx.port=4502 -e -Dapp.cms.myproject.complete.version=${version}
For publish deployment -
-U clean install -Pinstall-myproject-complete -Dcrx.host=${host}-publish.mysite.com -Dcrx.port=4503 -e -Dapp.cms.myproject.complete.version=${version}
This is the base configuration, you could further customize it to accept either the entire node_name/ip along with port information to keep a single pipleline for deployment