Developing with WinCC OA in Docker Containers

Running industrial SCADA systems on developer machines can sometimes lead to a cluttered host operating system, dependency conflicts, or difficulties in managing multiple software versions. WinCC Open Architecture (WinCC OA) is a powerful platform, and running it inside a Docker container for development is an elegant solution to these challenges.

In this post, we’ll walk through how to build a WinCC OA container image on your favorite Linux OS (like Ubuntu) and use a convenient access script to keep your projects organized and run GUI tools like the Console and Project Manager seamlessly.

Step 1: Building the WinCC OA Docker Image

Before running the container, we need to build the Docker image. Navigate to the directory where you downloaded and extracted the WinCC OA installation files (which should also contain your Dockerfile), and run the following command:

docker build --build-arg USER_ID=$(id -u) --build-arg USER_GID=$(id -g) --build-arg USER=$(whoami) --build-arg BASE_IMAGE=debian:trixie -t winccoa321 .

Why these build arguments? By matching the container’s user ID and group ID with your host user, we avoid file permission issues when editing files and mapping project volumes.

Step 2: Managing the Container with winccoa.sh

To automate starting, stopping, and entering the container, we use a custom shell script called winccoa.sh. This script takes care of several important development tasks:

    • Persistent Container Lifecycle: It checks if the container already exists. If it is stopped, it starts it. If it doesn’t exist, it creates a new one using the winccoa321 image. Since the container runs with sleep infinity, it remains active in the background.
    • Volume Mapping: Your host user home directory is mounted to the container (-v "$HOME:/home/$USER:rw"). This ensures your projects, configurations, and license files persist on the host system and can be edited with your favorite host IDEs (like VS Code).
    • Reusable Sessions: You can run the script to enter the running container terminal via docker exec -it winccoa bash, perform your tasks, and exit without stopping the container or losing state.

Note on configuration using a .env file: The script checks if a .env file exists in its directory and loads its environment variables (using set -a and source). This allows you to easily customize variables such as CONTAINER_NAME, WCC_OA_IMAGE, or WCC_OA_VERSION without having to modify the shell script itself.

Here is the full winccoa.sh script:

#!/bin/bash

# WinCC OA Container Access Script
# Provides terminal access to the WinCC OA Docker container with volume mapping

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# Default configuration
CONTAINER_NAME="${1:-winccoa}"
WCC_OA_IMAGE="${WCC_OA_IMAGE:-winccoa321}"
WCC_OA_VERSION="${WCC_OA_VERSION:-3.21}"
HOME_DIR="/home/$USER"

# Load .env file if it exists
if [ -f "$SCRIPT_DIR/.env" ]; then
    set -a
    source "$SCRIPT_DIR/.env"
    set +a
fi

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

echo -e "${GREEN}WinCC OA Container Access${NC}"
echo "======================================"
echo "Container: $CONTAINER_NAME"
echo ""

# Check if Docker is running
if ! docker info > /dev/null 2>&1; then
    echo -e "${RED}Error: Docker daemon is not running${NC}"
    exit 1
fi

# Check if container exists using docker inspect
if docker inspect $CONTAINER_NAME > /dev/null 2>&1; then
    echo -e "${GREEN}✓ Container exists${NC}"

    # Check if it's running
    if [ "$(docker inspect -f '{{.State.Running}}' $CONTAINER_NAME)" = "true" ]; then
        echo -e "${GREEN}✓ Container is running${NC}"
    else
        echo -e "${YELLOW}Starting existing container...${NC}"
        docker start $CONTAINER_NAME
        echo -e "${GREEN}✓ Container started${NC}"
    fi
else
    echo -e "${YELLOW}Container does not exist, creating new one...${NC}"
    docker create \
        --name $CONTAINER_NAME \
        --network host \
        --entrypoint sleep \
        -e OAINST=/opt/WinCC_OA/$WCC_OA_VERSION \
        -e LANG=en_US.UTF-8 \
        -e LANGUAGE=en_US:en \
        -e LC_ALL=en_US.UTF-8 \
        -e DISPLAY=:0 \
        -e PATH=/opt/WinCC_OA/$WCC_OA_VERSION/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
        -v "$HOME_DIR:/home/$USER:rw" \
        $WCC_OA_IMAGE infinity > /dev/null

    docker start $CONTAINER_NAME
    echo -e "${GREEN}✓ Container created and started${NC}"
fi

echo ""
echo -e "${GREEN}Entering container terminal...${NC}"
echo "Type 'exit' to return to this shell (container will keep running)"
echo "Volume mapped: $HOME_DIR"
echo "======================================"
echo ""

# Execute bash in container (container stays running when you exit)
docker exec -it $CONTAINER_NAME bash

echo ""
echo -e "${GREEN}Bash session ended (container is still running)${NC}"

Step 3: Running Graphical Tools (Console & Project Manager)

WinCC OA relies on graphical interfaces for project management and engineering. The script passes your host’s DISPLAY environment variable and network configuration to the container so that X11 applications can render on your host screen.

However, X11 security will block the container from connecting by default. To authorize the container, you must run the following command in a terminal session on your host machine before starting GUI tools:

xhost +

Once authorized, you can run commands like startPA inside the container, and the Project Manager window will appear on your desktop as if it were running natively.

Summary

Running WinCC OA in a container gives you a clean, isolated environment for SCADA development. Volume mapping keeps your code safe on the host machine, and X11 forwarding gives you access to the full suite of graphical development tools without the overhead of a virtual machine.