How do I make a Python Docker image an OpenWhisk action?
<p>I have a Docker image  which runs a Python program. I want now to run this container as an OpenWhisk action. How do I do this?  </p>

<p>I have seen several examples in other programming languages, and an excellent <a href="http://blog.altoros.com/how-to-use-openwhisk-docker-actions-in-ibm-bluemix.html" rel="nofollow">black box</a> skeleton approach in C and Node.js. but I want to understand more about how OpenWhisk interacts with the container and, if possible, employ just Python.</p>

<p>It's a lot simpler now (Sept 2016) than in my previous answer.</p>

<p>After having  created the <code>dockerSkeleton</code> directory with the command <code>$ wsk sdk install docker</code> all you have to do is to edit the <code>Dockerfile</code> and make sure your Python (2.7 right now)  is accepting parameters and supplying outputs in the appropriate format.</p>

<p>Here's a summary. I've written it up in greater detail <a href="https://github.com/iainhouston/dockerPython" rel="nofollow">here on GitHub</a></p>

<h3>The program</h3>

<p>File <code>test.py</code> (or <code>whatever_name.py</code> you will use in your edited <code>Dockerfile</code> below.)  </p>

<ul>
<li>Make sure it's executable (<code>chmod a+x test.py</code>).</li>
<li>Make sure it's got the  shebang on line one.</li>
<li>Make sure it runs locally.   

<ul>
<li>e.g. <code>./test.py '{"tart":"tarty"}'</code><br>
produces the JSON dictionary:<br>
<code>{"allparams": {"tart": "tarty", "myparam": "myparam default"}}</code></li>
</ul></li>
</ul>

<pre> <code>
    #!/usr/bin/env python

    import sys
    import json

    def main():
      # accept multiple '--param's
      params = json.loads(sys.argv[1])
      # find 'myparam' if supplied on invocation
      myparam = params.get('myparam', 'myparam default')

      # add or update 'myparam' with default or 
      # what we were invoked with as a quoted string
      params['myparam'] = '{}'.format(myparam)

      # output result of this action
      print(json.dumps({ 'allparams' : params}))

    if __name__ == "__main__":
      main()
</code> </pre> 

<h3>The Dockerfile</h3>

<p>Compare the following with the supplied <code>Dockerfile</code> to take the Python script <code>test.py</code> and ready it to build the docker image.  </p>

<p>Hopefully the comments explain the differences. Any assets (data files or modules) in the current directory will become part of the image as will any Python dependencies listed in <code>requirements.txt</code></p>

<pre><code># Dockerfile for Python whisk docker action
FROM openwhisk/dockerskeleton

ENV FLASK_PROXY_PORT 8080

# Install our action's Python dependencies
ADD requirements.txt /action/requirements.txt
RUN cd /action; pip install -r requirements.txt

# Ensure source assets are not drawn from the cache 
# after this date
ENV REFRESHED_AT 2016-09-05T13:59:39Z
# Add all source assets
ADD . /action
# Rename our executable Python action
ADD test.py /action/exec

# Leave CMD as is for Openwhisk
CMD ["/bin/bash", "-c", "cd actionProxy &amp;&amp; python -u actionproxy.py"]
</code></pre>

<p>Note the <code>ENV REFRESHED_AT ...</code> which I used to make sure that an updated <code>test.py</code> layer is picked up afresh rather than being drawn from the cache when the image is built.</p>

python docker openwhisk