Merge pull request #14 from s-allius/reduze-size

Reduze size
This commit is contained in:
Stefan Allius
2023-10-07 23:10:40 +02:00
committed by GitHub
7 changed files with 69 additions and 44 deletions

View File

@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [0.2.0] - 2023-10-07
This version halves the size of the Docker image and reduces the attack surface for security vulnerabilities, by omitting unneeded code. The feature set is exactly the same as the previous release version 0.1.0.
### Changes
- move from slim-bookworm to an alpine base image
- install python requirements with pip wheel
- disable DEBUG log for releases
- support building of release candidates
## [0.1.0] - 2023-10-06 ## [0.1.0] - 2023-10-06
- refactoring of the connection classes - refactoring of the connection classes

View File

@@ -2,40 +2,41 @@ ARG SERVICE_NAME="tsun-proxy"
ARG UID=1000 ARG UID=1000
ARG GID=1000 ARG GID=1000
# set base image (host OS) #
FROM python:3.11-slim-bookworm AS builder # first stage for our base image
FROM python:3.11-alpine AS base
USER root USER root
# install gosu for a better su+exec command RUN apk update && \
RUN set -eux; \ apk upgrade
apt-get update; \ RUN apk add --no-cache su-exec
apt-get install -y gosu; \
rm -rf /var/lib/apt/lists/*; \
# verify that the binary works
gosu nobody true
RUN pip install --upgrade pip #
# second stage for building wheels packages
FROM base as builder
RUN apk add --no-cache build-base && \
python -m pip install --no-cache-dir -U pip wheel
# copy the dependencies file to the working directory # copy the dependencies file to the root dir and install requirements
COPY ./requirements.txt . COPY ./requirements.txt /root/
RUN python -OO -m pip wheel --no-cache-dir --wheel-dir=/root/wheels -r /root/requirements.txt
# install dependencies
RUN pip install --user -r requirements.txt
# #
# second unnamed stage # third stage for our runtime image
FROM python:3.11-slim-bookworm FROM base as runtime
ARG SERVICE_NAME ARG SERVICE_NAME
ARG VERSION ARG VERSION
ARG UID ARG UID
ARG GID ARG GID
ARG LOG_LVL
ENV VERSION=$VERSION ENV VERSION=$VERSION
ENV SERVICE_NAME=$SERVICE_NAME ENV SERVICE_NAME=$SERVICE_NAME
ENV UID=$UID ENV UID=$UID
ENV GID=$GID ENV GID=$GID
ENV LOG_LVL=$LOG_LVL
# set the working directory in the container # set the working directory in the container
@@ -43,18 +44,16 @@ WORKDIR /home/$SERVICE_NAME
# update PATH environment variable # update PATH environment variable
ENV HOME=/home/$SERVICE_NAME ENV HOME=/home/$SERVICE_NAME
ENV PATH=/home/$SERVICE_NAME/.local:$PATH
VOLUME ["/home/$SERVICE_NAME/log", "/home/$SERVICE_NAME/config"] VOLUME ["/home/$SERVICE_NAME/log", "/home/$SERVICE_NAME/config"]
# copy only the dependencies installation from the 1st stage image # install the requirements from the wheels packages from the builder stage
COPY --from=builder --chown=$SERVICE_NAME:$SERVICE_NAME /root/.local /home/$SERVICE_NAME/.local COPY --from=builder /root/wheels /root/wheels
COPY --from=builder /usr/sbin/gosu /usr/sbin/gosu RUN python -m pip install --no-cache --no-index /root/wheels/* && \
rm -rf /root/wheels
COPY entrypoint.sh /root/entrypoint.sh
RUN chmod +x /root/entrypoint.sh
# copy the content of the local src and config directory to the working directory # copy the content of the local src and config directory to the working directory
COPY --chmod=0700 entrypoint.sh /root/entrypoint.sh
COPY config . COPY config .
COPY src . COPY src .

View File

@@ -9,20 +9,22 @@ arr=(${VERSION//./ })
MAJOR=${arr[0]} MAJOR=${arr[0]}
IMAGE=tsun-gen3-proxy IMAGE=tsun-gen3-proxy
if [[ $1 == dev ]];then if [[ $1 == dev ]] || [[ $1 == rc ]] ;then
IMAGE=docker.io/sallius/${IMAGE} IMAGE=docker.io/sallius/${IMAGE}
VERSION=${VERSION}-dev VERSION=${VERSION}-$1
elif [[ $1 == rel ]];then elif [[ $1 == rel ]];then
IMAGE=ghcr.io/s-allius/${IMAGE} IMAGE=ghcr.io/s-allius/${IMAGE}
else else
echo argument missing! echo argument missing!
echo try: $0 '[dev|rel]' echo try: $0 '[dev|rc|rel]'
exit 1 exit 1
fi fi
echo version: $VERSION build-date: $BUILD_DATE image: $IMAGE echo version: $VERSION build-date: $BUILD_DATE image: $IMAGE
if [[ $1 == dev ]];then if [[ $1 == dev ]];then
docker build --build-arg "VERSION=${VERSION}" --label "org.label-schema.build-date=${BUILD_DATE}" --label "org.opencontainers.image.version=${VERSION}" -t ${IMAGE}:latest app docker build --build-arg "VERSION=${VERSION}" --build-arg "LOG_LVL=DEBUG" --label "org.label-schema.build-date=${BUILD_DATE}" --label "org.opencontainers.image.version=${VERSION}" -t ${IMAGE}:latest app
elif [[ $1 == rc ]];then
docker build --no-cache --build-arg "VERSION=${VERSION}" --label "org.label-schema.build-date=${BUILD_DATE}" --label "org.opencontainers.image.version=${VERSION}" -t ${IMAGE}:latest app
elif [[ $1 == rel ]];then elif [[ $1 == rel ]];then
docker build --no-cache --build-arg "VERSION=${VERSION}" --label "org.label-schema.build-date=${BUILD_DATE}" --label "org.opencontainers.image.version=${VERSION}" -t ${IMAGE}:latest -t ${IMAGE}:${MAJOR} -t ${IMAGE}:${VERSION} app docker build --no-cache --build-arg "VERSION=${VERSION}" --label "org.label-schema.build-date=${BUILD_DATE}" --label "org.opencontainers.image.version=${VERSION}" -t ${IMAGE}:latest -t ${IMAGE}:${MAJOR} -t ${IMAGE}:${VERSION} app
docker push ghcr.io/s-allius/tsun-gen3-proxy:latest docker push ghcr.io/s-allius/tsun-gen3-proxy:latest

View File

@@ -10,17 +10,15 @@ echo "#"
if [ "$user" = '0' ]; then if [ "$user" = '0' ]; then
mkdir -p /home/$SERVICE_NAME/log /home/$SERVICE_NAME/config mkdir -p /home/$SERVICE_NAME/log /home/$SERVICE_NAME/config
if id $SERVICE_NAME ; then if ! id $SERVICE_NAME &> /dev/null; then
echo "user still exists"
else
addgroup --gid $GID $SERVICE_NAME 2> /dev/null addgroup --gid $GID $SERVICE_NAME 2> /dev/null
adduser --ingroup $SERVICE_NAME --shell /bin/false --disabled-password --no-create-home --comment "" --uid $UID $SERVICE_NAME adduser -G $SERVICE_NAME -s /bin/false -D -H -g "" -u $UID $SERVICE_NAME
fi fi
chown -R $SERVICE_NAME:$SERVICE_NAME /home/$SERVICE_NAME || true chown -R $SERVICE_NAME:$SERVICE_NAME /home/$SERVICE_NAME || true
echo "######################################################" echo "######################################################"
echo "#" echo "#"
exec gosu $SERVICE_NAME "$@" exec su-exec $SERVICE_NAME "$@"
else else
exec "$@" exec "$@"
fi fi

View File

@@ -21,7 +21,7 @@ class AsyncStream(Message):
Our puplic methods Our puplic methods
''' '''
def set_serial_no(self, serial_no : str): def set_serial_no(self, serial_no : str):
logger.info(f'SerialNo: {serial_no}') logger.debug(f'SerialNo: {serial_no}')
if self.unique_id != serial_no: if self.unique_id != serial_no:
@@ -40,7 +40,7 @@ class AsyncStream(Message):
if not inverters['allow_all']: if not inverters['allow_all']:
self.unique_id = None self.unique_id = None
logger.error('ignore message from unknow inverter!') logger.warning(f'ignore message from unknow inverter! (SerialNo: {serial_no})')
return return
self.unique_id = serial_no self.unique_id = serial_no
@@ -67,7 +67,7 @@ class AsyncStream(Message):
except (ConnectionResetError, except (ConnectionResetError,
ConnectionAbortedError, ConnectionAbortedError,
RuntimeError) as error: RuntimeError) as error:
logger.error(f'In loop for {self.addr}: {error}') logger.warning(f'In loop for {self.addr}: {error}')
self.close() self.close()
return return
except Exception: except Exception:

View File

@@ -18,7 +18,8 @@ def hex_dump_memory(level, info, data, num):
lines = [] lines = []
lines.append(info) lines.append(info)
tracer = logging.getLogger('tracer') tracer = logging.getLogger('tracer')
if not tracer.isEnabledFor(level): return
#data = list((num * ctypes.c_byte).from_address(ptr)) #data = list((num * ctypes.c_byte).from_address(ptr))
@@ -294,7 +295,7 @@ class Message(metaclass=IterRegistry):
def msg_unknown(self): def msg_unknown(self):
logger.error (f"Unknow Msg: ID:{self.msg_id}") logger.warning (f"Unknow Msg: ID:{self.msg_id}")
self.forward(self._recv_buffer, self.header_len+self.data_len) self.forward(self._recv_buffer, self.header_len+self.data_len)

View File

@@ -32,8 +32,16 @@ def handle_SIGTERM(loop):
logging.info('Shutdown complete') logging.info('Shutdown complete')
def get_log_level() -> int:
'''checks if LOG_LVL is set in the environment and returns the corresponding logging.LOG_LEVEL'''
log_level = os.getenv('LOG_LVL', 'INFO')
if log_level== 'DEBUG':
log_level = logging.DEBUG
elif log_level== 'WARN':
log_level = logging.WARNING
else:
log_level = logging.INFO
return log_level
if __name__ == "__main__": if __name__ == "__main__":
@@ -41,11 +49,17 @@ if __name__ == "__main__":
# Setup our daily, rotating logger # Setup our daily, rotating logger
# #
serv_name = os.getenv('SERVICE_NAME', 'proxy') serv_name = os.getenv('SERVICE_NAME', 'proxy')
version = os.getenv('VERSION', 'unknown') version = os.getenv('VERSION', 'unknown')
logging.config.fileConfig('logging.ini') logging.config.fileConfig('logging.ini')
logging.info(f'Server "{serv_name} - {version}" will be started') logging.info(f'Server "{serv_name} - {version}" will be started')
logging.getLogger().setLevel(logging.DEBUG if __debug__ else logging.INFO)
# set lowest-severity for 'root', 'msg', 'conn' and 'data' logger
log_level = get_log_level()
logging.getLogger().setLevel(log_level)
logging.getLogger('msg').setLevel(log_level)
logging.getLogger('conn').setLevel(log_level)
logging.getLogger('data').setLevel(log_level)
# read config file # read config file
Config.read() Config.read()