Skip to content

Instantly share code, notes, and snippets.

@tayloraswift
Last active August 21, 2022 21:29
Show Gist options
  • Save tayloraswift/1e523b24edf6f429689648f74011e8ba to your computer and use it in GitHub Desktop.
Save tayloraswift/1e523b24edf6f429689648f74011e8ba to your computer and use it in GitHub Desktop.
vscode+docker tutorial

test project

  1. clone a swift project

installing code

  1. download from https://code.visualstudio.com/

setting up the vscode-swift extension

  1. go to the extensions sidebar 1.i. install the SSWG Swift extension

  2. open a swift project. highlighting is weird!

enabling semantic highlighting

swifties need specialized vscode themes. create your own vscode extension!

teach a woman how to fish:

git clone git@github.com:kelvin13/vs-swift-madrid-theme.git
cd vs-swift-madrid-theme
$ curl -sL https://deb.nodesource.com/setup_18.x | sudo -E bash -
$ sudo apt install nodejs

do not install the default version from apt! it is too old!

$ npm --version
8.15.0
$ node --version
v18.7.0
$ sudo npm install -g vsce
$ vsce package
 DONE  Packaged: /home/ubuntu/dev/vs-swift-madrid-theme/swift-madrid-theme-0.0.1.vsix (6 files, 6.69KB)

Extensions > > Install from VSIX

Settings > Workbench > Color Theme

go back to a(ny) swift file. everything is gray! how to fix?

swift is not installed!

installing swift

don’t install install swift globally! use DOCKER

  • install Remote - Containers vscode extension
  • install Docker vscode extension

installing docker

from: https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository

 $ sudo mkdir -p /etc/apt/keyrings
 $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
 $ echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt update 
$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
$ docker --version
Docker version 20.10.17, build 100c701

click on colorful >< icon (in lower-left corner), and run Reopen in Container

“Current user does not have permission to run 'docker'” “Try adding the user to the 'docker' group.”

do what it says:

(optional) show existing groups:

$ cat /etc/group

(optional) show groups you are a member of:

$ groups
ubuntu adm cdrom sudo dip plugdev lpadmin lxd sambashare

(optional) show groups root is a member of:

$ groups root
root : root

add yourself to the docker group (same as -aG):

$ sudo usermod --append --groups docker $USER
$ groups
ubuntu adm cdrom sudo dip plugdev lpadmin lxd sambashare
$ groups $USER
ubuntu : ubuntu adm cdrom sudo dip plugdev lpadmin lxd sambashare docker

different? REBOOT/LOGOUT

can i use docker yet?

$ groups
ubuntu adm cdrom sudo dip plugdev lpadmin lxd sambashare docker

YES

setting up swift in docker

setting up swift in docker is easy to fuck up. here is the right way to do it:

  1. create .devcontainer/ directory
  2. create .devcontainer/dockerfile:
FROM amazonlinux:latest

RUN yum -y update 
# install sysadmin basics 
RUN yum -y install sudo useradd passwd 
# install swift dependencies
RUN yum -y install \
    binutils \
    gcc \
    git \
    unzip \
    glibc-static \
    gzip \
    libbsd \
    libcurl-devel \
    libedit \
    libicu \
    libsqlite \
    libstdc++-static \
    libuuid \
    libxml2-devel \
    tar \
    tzdata \
    zlib-devel

# create the `ec2-user`, and switch to her
RUN useradd -ms /bin/bash ec2-user
RUN passwd -d ec2-user
RUN usermod -aG wheel ec2-user
USER ec2-user

WORKDIR /home/ec2-user/
# download a copy of `swiftenv`
ADD https://github.com/kylef/swiftenv/archive/1.5.0.tar.gz swiftenv.tar.gz 
# allow `ec2-user` to access it
RUN sudo chown ec2-user swiftenv.tar.gz

# also overrides any `.swift-version` local configurations
ENV SWIFT_VERSION DEVELOPMENT-SNAPSHOT-2022-08-15-a
ENV SWIFTENV_ROOT /home/ec2-user/.swiftenv
# install `swiftenv`
RUN mkdir -p $SWIFTENV_ROOT
RUN tar -xzf swiftenv.tar.gz -C $SWIFTENV_ROOT --strip 1
RUN rm swiftenv.tar.gz
ENV PATH $SWIFTENV_ROOT/bin:$SWIFTENV_ROOT/shims:$PATH
# install `swift`
RUN swiftenv install https://download.swift.org/development/amazonlinux2/swift-$SWIFT_VERSION/swift-$SWIFT_VERSION-amazonlinux2.tar.gz

# optional, but python, and iptables are very useful in a container
RUN sudo yum -y install python3 libpython3-dev iptables nc

# generate script that will run on terminal creation, 
# enables showing the PWD prompt
RUN echo "PS1='\w\$ '" >> .bashrc
RUN echo "force_color_prompt=yes" >> .bashrc
ENV TERM xterm-256color
# generate script that will run on container startup
RUN echo 'sudo iptables -t nat -A PREROUTING -p tcp --dport  80 -j REDIRECT --to-port 8080' >> setup
RUN echo 'sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8443' >> setup
RUN echo 'sleep infinity' >> setup
RUN chmod +x setup 

CMD ./setup

now we have TWO ways to switch between swift toolchains: we can switch between docker containers and we can switch between swiftenv versions. WHY? because we will not use docker on AWS, docker is just for us developing. and on AWS you still need to switch between swift versions.

WHY jump through all sysadmin hoops in dockerfile instead of using official swift images? because we want to replicate the deployment environment as much as possible.

  1. create .devcontainer/docker-compose.yml:
version: "3.9"
services:
    swift: 
        image: swift-2022-08-15-a
        build:
            dockerfile: 'dockerfile'
        volumes:
            - ..:/workspace
        cap_add:
            - NET_ADMIN

WHY use docker compose? why not just use docker directly? because you will need other services soon and the dockerfile can get really cluttered. and if you change the commands before downloading the swift toolchain, you have to redownload the entire toolchain.

build: dockerfile: path to dockerfile. it can live ANYWHERE!

volumes: LHS is directory to mount, .. is the project directory. RHS /workspace is where it appears inside the container. /workspace is outside ec2-user’s home directory, but that’s okay!

cap_add: (optional) lets us use iptables

  1. create .devcontainer/devcontainer.json:
{
    "name": "swift-container",
    "dockerComposeFile": "docker-compose.yml",
    "service": "swift",
    "workspaceFolder": "/workspace",
    "remoteUser": "ec2-user",
    "extensions": 
    [
      "sswg.swift-lang"
    ]
}

run Reopen in Container

oh no!

Failed to setup CodeLLDB for debugging of Swift code. Debugging may produce unexpected results. Error: "LLDB failed to provide a library path"

this is a vscode-swift bug. add settings to workaround:

{
    "name": "swift-container",
    "dockerComposeFile": "docker-compose.yml",
    "service": "swift",
    "workspaceFolder": "/workspace",
    "remoteUser": "ec2-user",
    "extensions": 
    [
      "sswg.swift-lang"
    ],
    "settings": 
    {
        // needed due to https://github.com/swift-server/vscode-swift/issues/365
        "swift.path": "/home/ec2-user/.swiftenv/versions/DEVELOPMENT-SNAPSHOT-2022-08-15-a/usr/bin",
        // needed to suppress vscode-swift warning
        "lldb.library": "/home/ec2-user/.swiftenv/versions/DEVELOPMENT-SNAPSHOT-2022-08-15-a/usr/lib/liblldb.so"
    }
}

the toolchain tags have to be hardcoded, because the vscode swift extension can’t understand $HOME or $SWIFT_VERSION. and we cannot point it to the swiftenv shim instead, because of swiftlang/vscode-swift#365 . this is retarded, but this is just an vscode extension bug we have to live with.

REBUILD container (don’t just restart). container should work fine now.

binding to http/https ports

usually, you want the app to bind to a high port (like 8080) from the inside, but have it be accessed from the normal (low) port. the iptables PREROUTING does this from the inside of the container, but we still have to open ports 80 and 443 on the outside of the container. this is easy, just add ports: to docker-compose.yml:

version: "3.9"
services:
    swift: 
        image: swift-2022-08-15-a
        build:
            dockerfile: 'dockerfile'
        volumes:
            - ..:/workspace
        cap_add:
            - NET_ADMIN
        ports: 
            - '80:80'
            - '443:443'

to test:

$ sudo nc -l 8080

inside the container, and then go to http://127.0.0.1:80 or http://0.0.0.0:80 in firefox, and nc will show

$ sudo nc -l 8080
GET / HTTP/1.1
Host: 0.0.0.0
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:103.0) Gecko/20100101 Firefox/103.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Connection: keep-alive
Upgrade-Insecure-Requests: 1

incremental builds

incremental builds used to not work in docker, because it would change the inode numbers every time the container restarts.

in newer versions of docker, incremental swift builds should just work. if you are not getting incremental builds, try upgrading docker to its latest version (20.10).

miscellaneous

turning off colored brackets

search for bracketPairColorization in settings, then uncheck the box.

turning off inlay hints

sourcekit-lsp generates superfluous inlay hints.

image

turn them off in settings > Editor >> Inlay Hints:Enabled

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment